From 48904b10f032f9623d3c11430a1fb28434f0aa98 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Sat, 30 Nov 2024 12:12:13 -0600 Subject: [PATCH] remove sokol, use sdl3 --- meson.build | 25 +- mingw32.cross | 4 +- scripts/base.js | 1 + scripts/engine.js | 70 +- scripts/layout.js | 20 +- scripts/profile.js | 1 - scripts/prosperon.js | 16 +- scripts/render.js | 120 +- scripts/std.js | 11 +- source/HandmadeMath.h | 2 +- source/config.c | 9 - source/datastream.c | 14 +- source/datastream.h | 6 - source/font.c | 87 +- source/font.h | 21 +- source/gif_load.h | 299 - source/jsffi.c | 2227 +- source/model.c | 55 +- source/model.h | 7 +- source/qjs_macros.h | 18 +- source/qjs_tracy.c | 10 +- source/render.c | 66 - source/render.h | 18 +- source/render_trace.cpp | 1 - source/script.c | 3 - source/texture.c | 311 +- source/texture.h | 18 +- source/thirdparty/sokol/.editorconfig | 9 - .../sokol/.github/workflows/gen_bindings.yml | 331 - .../sokol/.github/workflows/main.yml | 65 - source/thirdparty/sokol/.gitignore | 7 - source/thirdparty/sokol/CHANGELOG.md | 2692 --- source/thirdparty/sokol/LICENSE | 22 - source/thirdparty/sokol/README.md | 406 - source/thirdparty/sokol/fips.yml | 2 - source/thirdparty/sokol/sokol_app.h | 12097 ---------- source/thirdparty/sokol/sokol_args.h | 867 - source/thirdparty/sokol/sokol_audio.h | 2612 --- source/thirdparty/sokol/sokol_fetch.h | 2819 --- source/thirdparty/sokol/sokol_gfx.h | 19540 ---------------- source/thirdparty/sokol/sokol_glue.h | 162 - source/thirdparty/sokol/sokol_log.h | 343 - source/thirdparty/sokol/sokol_time.h | 319 - source/thirdparty/sokol/util/sokol_color.h | 1148 - .../thirdparty/sokol/util/sokol_debugtext.h | 4567 ---- .../thirdparty/sokol/util/sokol_fontstash.h | 1789 -- .../thirdparty/sokol/util/sokol_gfx_imgui.h | 4765 ---- source/thirdparty/sokol/util/sokol_gl.h | 4329 ---- source/thirdparty/sokol/util/sokol_imgui.h | 3151 --- source/thirdparty/sokol/util/sokol_memtrack.h | 167 - source/thirdparty/sokol/util/sokol_shape.h | 1431 -- source/thirdparty/sokol/util/sokol_spine.h | 5949 ----- source/tinydir.h | 848 - source/yugine.c | 6 + subprojects/chipmunk.wrap | 2 + 55 files changed, 1462 insertions(+), 72423 deletions(-) delete mode 100644 source/gif_load.h delete mode 100644 source/thirdparty/sokol/.editorconfig delete mode 100644 source/thirdparty/sokol/.github/workflows/gen_bindings.yml delete mode 100644 source/thirdparty/sokol/.github/workflows/main.yml delete mode 100644 source/thirdparty/sokol/.gitignore delete mode 100644 source/thirdparty/sokol/CHANGELOG.md delete mode 100644 source/thirdparty/sokol/LICENSE delete mode 100644 source/thirdparty/sokol/README.md delete mode 100644 source/thirdparty/sokol/fips.yml delete mode 100644 source/thirdparty/sokol/sokol_app.h delete mode 100644 source/thirdparty/sokol/sokol_args.h delete mode 100644 source/thirdparty/sokol/sokol_audio.h delete mode 100644 source/thirdparty/sokol/sokol_fetch.h delete mode 100644 source/thirdparty/sokol/sokol_gfx.h delete mode 100644 source/thirdparty/sokol/sokol_glue.h delete mode 100644 source/thirdparty/sokol/sokol_log.h delete mode 100644 source/thirdparty/sokol/sokol_time.h delete mode 100644 source/thirdparty/sokol/util/sokol_color.h delete mode 100644 source/thirdparty/sokol/util/sokol_debugtext.h delete mode 100644 source/thirdparty/sokol/util/sokol_fontstash.h delete mode 100644 source/thirdparty/sokol/util/sokol_gfx_imgui.h delete mode 100644 source/thirdparty/sokol/util/sokol_gl.h delete mode 100644 source/thirdparty/sokol/util/sokol_imgui.h delete mode 100644 source/thirdparty/sokol/util/sokol_memtrack.h delete mode 100644 source/thirdparty/sokol/util/sokol_shape.h delete mode 100644 source/thirdparty/sokol/util/sokol_spine.h delete mode 100644 source/tinydir.h create mode 100644 subprojects/chipmunk.wrap diff --git a/meson.build b/meson.build index 2a93db1d..e01ff72f 100644 --- a/meson.build +++ b/meson.build @@ -60,10 +60,23 @@ if storefront == 'steam' deps += dependency('qjs-steam',static:false) endif +cmake = import('cmake') +#cmake_ozz = cmake.subproject('ozz') + deps += dependency('qjs-layout',static:true) deps += dependency('qjs-nota',static:true) deps += dependency('qjs-miniz',static:true) deps += dependency('qjs-soloud',static:true) +deps += dependency('sdl3') +#deps += cc.find_library('openblas') +deps += dependency('cblas') +deps += dependency('physfs',static:true) +#deps += cmake_ozz.dependency('ozz_base') +#deps += dependency('sdl2_image') +#deps += dependency('ogg') # for sdl2_mixer +#deps += dependency('sdl2_mixer') +#deps += dependency('sdl2_ttf') + deps += dependency('threads') @@ -76,14 +89,14 @@ if get_option('enet') endif sources = [] -src += ['anim.c', 'config.c', 'datastream.c','font.c','gameobject.c','HandmadeMath.c','jsffi.c','model.c','render.c','render_trace.cpp','script.c','simplex.c','spline.c','texture.c', 'timer.c', 'transform.c','warp.c','yugine.c', 'glad.c', 'wildmatch.c'] +src += ['anim.c', 'config.c', 'datastream.c','font.c','gameobject.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c','texture.c', 'timer.c', 'transform.c','warp.c','yugine.c', 'glad.c', 'wildmatch.c'] imsrc = ['GraphEditor.cpp','ImCurveEdit.cpp','ImGradient.cpp','imgui_draw.cpp','imgui_tables.cpp','imgui_widgets.cpp','imgui.cpp','ImGuizmo.cpp','imnodes.cpp','implot_items.cpp','implot.cpp'] srceng = 'source' tp = srceng / 'thirdparty' -includes = [srceng,tp / 'cgltf',tp / 'imgui',tp / 'par',tp / 'sokol',tp / 'stb',tp,tp / 'pl_mpeg/include'] +includes = [srceng,tp / 'cgltf',tp / 'imgui',tp / 'par',tp / 'stb',tp,tp / 'pl_mpeg/include'] foreach file : src full_path = join_paths('source', file) @@ -91,10 +104,10 @@ foreach file : src endforeach if get_option('editor') - sources += 'source/qjs_imgui.cpp' - foreach imgui : imsrc - sources += tp / 'imgui' / imgui - endforeach +# sources += 'source/qjs_imgui.cpp' +# foreach imgui : imsrc +# sources += tp / 'imgui' / imgui +# endforeach deps += dependency('qjs-dmon',static:true) endif diff --git a/mingw32.cross b/mingw32.cross index 5c86b099..68686a7e 100644 --- a/mingw32.cross +++ b/mingw32.cross @@ -5,6 +5,7 @@ ar = 'x86_64-w64-mingw32-ar' windres = 'x86_64-w64-mingw32-windres' strip = 'x86_64-w64-mingw32-strip' exe_wrapper = 'wine' +pkgconfig = 'x86_64-w64-mingw32-pkg-config' [host_machine] system = 'windows' @@ -14,4 +15,5 @@ endian = 'little' [properties] link_args = ['-static'] -needs_exe_wrapper = false \ No newline at end of file +needs_exe_wrapper = false +pkg_config_libdir = '/usr/local/lib64/pkgconfig' diff --git a/scripts/base.js b/scripts/base.js index bab3cb9b..e63e8286 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -838,6 +838,7 @@ function make_swizz() { function arrsetelem(str, n) { Object.defineProperty(Array.prototype, str, setelem(n)); +// Object.defineProperty(Float32Array.prototype, setelem(n)); } var arr_elems = ["x", "y", "z", "w"]; diff --git a/scripts/engine.js b/scripts/engine.js index ab8ba5d6..f26f6c28 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -323,16 +323,6 @@ globalThis.use = function use(file) { return ret; }; -var allpaths = io.ls(); -allpaths = [...new Set(allpaths)] -//console.log(`found ${allpaths.length} files`); -//console.log(json.encode(allpaths)) - -io.exists = function(path) -{ - return allpaths.includes(path);// || core_db.exists(path); -} - var tmpslurp = io.slurp; io.slurp = function slurp(path) { @@ -349,43 +339,14 @@ io.slurpbytes = function(path) return ret; } -var ignore = io.slurp('.prosperonignore') -if (ignore) { - ignore = ignore.split('\n'); - for (var ig of ignore) { - if (!ig) continue; - allpaths = allpaths.filter(x => !x.startsWith(ig)); - } -} - -//var coredata = tmpslurp("core.zip"); -//var core_db = miniz.read(coredata); - -io.globToRegex = function globToRegex(glob) { - // Escape special regex characters - // Replace glob characters with regex equivalents - let regexStr = glob - .replace(/[\.\\]/g, "\\$&") // Escape literal backslashes and dots - .replace(/([^\*])\*/g, "$1[^/]*") // * matches any number of characters except / - .replace(/\*\*/g, ".*") // ** matches any number of characters, including none - .replace(/\[(.*?)\]/g, "[$1]") // Character sets - .replace(/\?/g, "."); // ? matches any single character - - // Ensure the regex matches the whole string - regexStr = "^" + regexStr + "$"; - - // Create and return the regex object - return new RegExp(regexStr); -}; - +var ignore = io.slurp('.prosperonignore').split('\n'); +var allpaths = io.globfs(ignore); var tmpglob = io.glob; io.glob = function glob(pat) { - return allpaths.filter(str => tmpglob(pat,str)).sort(); +// var allpaths = io.globfs(ignore); + return allpaths.filter(str => game.glob(pat,str)).sort(); } -console.log(io.glob("sprites/*.png")) -console.log(io.glob("**/render.js")) - function splitPath(path) { return path.split('/').filter(part => part.length > 0); } @@ -441,25 +402,6 @@ function matchPath(pathParts, patternParts) { return patternIndex === patternParts.length; } -function doglob(pattern) { - const patternParts = splitPattern(pattern); - const matches = []; - console.log("DOGLOB"); - - for (let i = 0; i < allpaths.length; i++) { - const path = allpaths[i]; - const pathParts = splitPath(path); - console.log(`testing ${json.encode(pathParts)} to ${json.encode(patternParts)}`); - if (matchPath(pathParts, patternParts)) { - - matches.push(path); - } - } - - // Optional: Sort the matches if needed - return matches.sort(); -} - function stripped_use(file, script) { file = Resources.find_script(file); @@ -477,11 +419,15 @@ function stripped_use(file, script) { } function bare_use(file) { + try { var script = io.slurp(file); if (!script) return; var fnname = file.replace(/[^a-zA-Z0-9_$]/g, "_"); script = `(function ${fnname}() { var self = this; ${script}; })`; Object.assign(globalThis, os.eval(file, script)()); + } catch(e) { + console.log(e); + } } profile.enabled = true; diff --git a/scripts/layout.js b/scripts/layout.js index ccbe046f..9d3a8b87 100644 --- a/scripts/layout.js +++ b/scripts/layout.js @@ -74,8 +74,6 @@ clay.draw = function draw(size, fn) box.marginbox.y -= margin.t; box.marginbox.width += margin.l+margin.r; box.marginbox.height += margin.t+margin.b; - box.content.y *= -1; - box.boundingbox.y *= -1 box.content.anchor_y = 1; box.boundingbox.anchor_y = 1; } @@ -181,7 +179,7 @@ clay.image = function image(path, ...configs) { var config = rectify_configs(configs); var image = game.texture(path); - config.image = path; + config.image = image; config.size ??= [image.texture.width, image.texture.height]; add_item(config); } @@ -223,9 +221,13 @@ layout.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos) { for (var cmd of cmds) { var boundingbox = geometry.rect_move(cmd.boundingbox,pos); +// boundingbox.x -= boundingbox.width*pos.anchor_x; +// boundingbox.y += boundingbox.height*pos.anchor_y; var content = geometry.rect_move(cmd.content,pos); +// content.x -= content.width*pos.anchor_x; +// content.y += content.height*pos.anchor_y; var config = cmd.config; - + if (config.hovered && geometry.rect_point_inside(boundingbox, mousepos)) { config.hovered.__proto__ = config; config = config.hovered; @@ -256,8 +258,14 @@ layout.draw_debug = function draw_debug(cmds, pos = [0,0]) { for (var i = 0; i < cmds.length; i++) { var cmd = cmds[i]; - render.rectangle(geometry.rect_move(cmd.content,pos), dbg_colors.content); - render.rectangle(geometry.rect_move(cmd.boundingbox,pos), dbg_colors.boundingbox); + var boundingbox = geometry.rect_move(cmd.boundingbox,pos); +// boundingbox.x -= boundingbox.width*pos.anchor_x; +// boundingbox.y += boundingbox.height*pos.anchor_y; + var content = geometry.rect_move(cmd.content,pos); +// content.x -= content.width*pos.anchor_x; +// content.y += content.height*pos.anchor_y; + render.rectangle(content, dbg_colors.content); + render.rectangle(boundingbox, dbg_colors.boundingbox); // render.rectangle(geometry.rect_move(cmd.marginbox,pos), dbg_colors.margin); } } diff --git a/scripts/profile.js b/scripts/profile.js index 5ff06f3b..29b77d36 100644 --- a/scripts/profile.js +++ b/scripts/profile.js @@ -86,7 +86,6 @@ function add_callgraph(fn, line, time, alone) { var hittar = 500; // number of call instructions before getting a new frame var hitpct = 0.2; // amount to randomize it -var start_gather = profile.now(); profile.cpu_start = undefined; diff --git a/scripts/prosperon.js b/scripts/prosperon.js index fb58ffc2..5b07f743 100644 --- a/scripts/prosperon.js +++ b/scripts/prosperon.js @@ -61,7 +61,7 @@ sim.stepping = function () { return this.mode === "step"; }; -var frame_t = profile.secs(profile.now()); +var frame_t = profile.now(); var physlag = 0; @@ -79,7 +79,7 @@ prosperon.SIGSEGV = function() prosperon.init = function () { render.init(); - imgui.init(); +// imgui.init(); tracy.gpu_init(); globalThis.audio = use("sound.js"); @@ -114,6 +114,8 @@ prosperon.init = function () { }; if (io.exists("game.js")) global.app = actor.spawn("game.js"); else global.app = actor.spawn("nogame.js"); + + console.log(io.exists("game.js")) }; prosperon.release_mode = function () { @@ -320,6 +322,16 @@ game.texture = function texture(path) { var parts = path.split(':'); path = Resources.find_image(parts[0]); + if (game.texture.cache[path]) return game.texture.cache[path]; + var newimg = {}; + var data = io.slurpbytes(path); + newimg.surface = os.make_texture(data); + newimg.texture = render._main.load_texture(newimg.surface); + game.texture.cache[path] = newimg; + console.log(newimg.texture.width); + console.log(newimg.texture.height); + return newimg; + // Look for a cached version var frame; var anim_str; diff --git a/scripts/render.js b/scripts/render.js index 08336221..68b38d8a 100644 --- a/scripts/render.js +++ b/scripts/render.js @@ -644,6 +644,7 @@ var polyssboshader; var sprite_ssbo; render.init = function () { + return; textshader = make_shader("text_base.cg"); render.spriteshader = make_shader("sprite.cg"); spritessboshader = make_shader("sprite_ssbo.cg"); @@ -828,24 +829,12 @@ function flush_poly() { } render.line = function render_line(points, color = Color.white, thickness = 1, shader = polyssboshader, pipe = base_pipeline) { - for (var i = 0; i < points.length - 1; i++) { - var a = points[i]; - var b = points[i + 1]; - var poly = poly_e(); - var dist = vector.distance(a, b); - poly.transform.move(vector.midpoint(a, b)); - poly.transform.rotate([0, 0, 1], vector.angle([b.x - a.x, b.y - a.y])); - poly.transform.scale = [dist, thickness, 1]; - poly.color = color; - } - queued_shader = shader; - queued_pipe = pipe; - check_flush(flush_poly); + render._main.line(points, color); }; /* All draw in screen space */ render.point = function (pos, size, color = Color.blue) { - render.circle(pos, size, size, color); + render._main.point(pos,color); }; render.cross = function render_cross(pos, size, color = Color.red, thickness = 1) { @@ -872,15 +861,14 @@ render.coordinate = function render_coordinate(pos, size, color) { var queued_shader; var queued_pipe; render.rectangle = function render_rectangle(rect, color = Color.white, shader = polyssboshader, pipe = base_pipeline) { - var poly = poly_e(); - poly.transform.rect(rect); - poly.color = color; - queued_shader = shader; - queued_pipe = pipe; - check_flush(flush_poly); + render._main.fillrect(rect,color); }; render.text = function text(str, rect, font = cur_font, size = 0, color = Color.white, wrap = -1, ) { + var pos = [rect.x,rect.y]; + render._main.fasttext(str, pos, color); + return; + if (typeof font === 'string') font = render.get_font(font); @@ -889,7 +877,7 @@ render.text = function text(str, rect, font = cur_font, size = 0, color = Color. pos.y -= font.descent; if (rect.anchor_y) pos.y -= rect.anchor_y*(font.ascent-font.descent); - gui.text(str, pos, size, color, wrap, font); // this puts text into buffer + os.make_text_buffer(str, pos, size, color, wrap, font); // this puts text into buffer cur_font = font; check_flush(render.flush_text); }; @@ -1018,7 +1006,8 @@ function calc_image_size(img) return [img.texture.width*img.rect.width, img.texture.height*img.rect.height]; } -render.image = function image(image, rect = [0,0], rotation = 0, color = Color.white) { +render.tile = function tile(image, rect = [0,0], color = Color.white) +{ if (!image) throw Error ('Need an image to render.') if (typeof image === "string") image = game.texture(image); @@ -1040,6 +1029,39 @@ render.image = function image(image, rect = [0,0], rotation = 0, color = Color.w lasttex = tex; } + render._main.tile(image.texture, rect, image.rect, 1); + return; +} + +render.image = function image(image, rect = [0,0], rotation = 0, color) { + if (!image) throw Error ('Need an image to render.') + if (typeof image === "string") + image = game.texture(image); + + rect.__proto__ = image.texture; + render._main.texture(image.texture, rect, image.rect, color); + return; + + var tex = image.texture; + if (!tex) return; + + var image_size = calc_image_size(image); //image.size; + + var size = [rect.width ? rect.width : image_size.x, rect.height ? rect.height : image_size.y]; + + if (!lasttex) { + check_flush(flush_img); + lasttex = tex; + } + + if (lasttex !== tex) { + flush_img(); + lasttex = tex; + } + + render._main.texture(image.texture, rect, image.rect); + return; + var e = img_e(); var pos = [rect.x,rect.y].sub(size.scale([rect.anchor_x, rect.anchor_y])); e.transform.trs(pos, undefined, size); @@ -1149,11 +1171,13 @@ render.get_font = function get_font(path,size) size = Number(parts[1]); } path = Resources.find_font(path); - var fontstr = `${path}.${size}`; + var fontstr = `${path}.${size}`; + console.log(`getting ${fontstr}`); if (fontcache[fontstr]) return fontcache[fontstr]; var data = io.slurpbytes(path); fontcache[fontstr] = os.make_font(data,size); + fontcache[fontstr].texture = render._main.load_texture(fontcache[fontstr].surface); return fontcache[fontstr]; } @@ -1396,10 +1420,13 @@ var imgui_fn = function imgui_fn() { prosperon.window_render(basesize.scale(mult)); */ +var clearcolor = [100,149,237,255].scale(1/255); prosperon.render = function prosperon_render() { try{ - render.glue_pass(); - render.set_view(prosperon.camera.transform); +// render.glue_pass(); + render._main.draw_color(clearcolor); + render._main.clear(); +/* render.set_view(prosperon.camera.transform); render.set_projection_ortho({ l:-prosperon.camera.size.x/2, r:prosperon.camera.size.x/2, @@ -1409,22 +1436,24 @@ try{ render.viewport(prosperon.camera.view(), false); if (render.draw_sprites) render.sprites(); - prosperon.draw(); - if (render.draw_particles) draw_emitters(); + + if (render.draw_particles) draw_emitters(); +*/ // render.fillmask(0); - render.forceflush(); - render.set_projection_ortho({ +// render.forceflush(); +/* render.set_projection_ortho({ l:0, r:prosperon.camera.size.x, b:-prosperon.camera.size.y, t:0 },-1,1); - - render.set_view(unit_transform); +*/ +// render.set_view(unit_transform); + prosperon.draw(); if (render.draw_hud) prosperon.hud(); - render.forceflush(); +// render.forceflush(); - render.set_projection_ortho({ +/* render.set_projection_ortho({ l:0, r:prosperon.size.x, b:-prosperon.size.y, @@ -1436,9 +1465,10 @@ try{ width:prosperon.size.x, l:0 }, false); - prosperon.app(); - render.forceflush(); - if (debug.show) imgui_fn(); +*/ +// prosperon.app(); +// render.forceflush(); +// if (debug.show) imgui_fn(); } catch(e) { throw e; } finally { @@ -1448,8 +1478,9 @@ try{ var texdata = os.tex_data(tex) tracy.image(texdata, tex.width, tex.height); */ - render.end_pass(); - render.commit(); +// render.end_pass(); +// render.commit(); + render._main.present(); endframe(); tracy.gpu_collect(); tracy.end_frame(); @@ -1482,10 +1513,8 @@ prosperon.process = function process() { layout.newframe(); // check for hot reloading if (dmon) dmon.poll(dmon_cb); - var dt = profile.secs(profile.now()) - frame_t; - frame_t = profile.secs(profile.now()); - - var sst = profile.now(); + var dt = profile.now() - frame_t; + frame_t = profile.now(); prosperon.appupdate(dt); input.procdown(); @@ -1496,9 +1525,6 @@ prosperon.process = function process() { if (sim.mode === "step") sim.pause(); } - profile.pushdata(profile.data.cpu.scripts, profile.now() - sst); - sst = profile.now(); - if (sim.mode === "play" || sim.mode === "step") { /* physlag += dt; @@ -1508,14 +1534,10 @@ prosperon.process = function process() { prosperon.phys2d_step(physics.delta * game.timescale); prosperon.physupdate(physics.delta * game.timescale); } - - profile.pushdata(profile.data.cpu.physics, profile.now() - sst); - sst = profile.now(); */ } tracy.gpu_zone(prosperon.render); -// prosperon.render(); }; return { render }; diff --git a/scripts/std.js b/scripts/std.js index cdfa03cf..4d69bb48 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -301,8 +301,15 @@ Cmdline.register_order( if (io.exists("config.js")) global.mixin("config.js"); else console.warn("No config.js file found. Starting with default parameters."); - - game.engine_start(prosperon); + var window = game.engine_start(prosperon); + console.log(game.renderers()); + console.log(game.cameras()); + var renderer = window.make_renderer("gpu"); + render._main = renderer; + + prosperon.init(); + + while(1) prosperon.process(); }, "Play the game present in this folder.", ); diff --git a/source/HandmadeMath.h b/source/HandmadeMath.h index f461fc19..b700162f 100644 --- a/source/HandmadeMath.h +++ b/source/HandmadeMath.h @@ -65,7 +65,7 @@ LICENSE - This software is in the public domain. Where that dedication is not + This software is in the public domain. Where that dedictaion is not recognized, you are granted a perpetual, irrevocable license to copy, distribute, and modify this file as you see fit. diff --git a/source/config.c b/source/config.c index 77c6977d..3451d647 100644 --- a/source/config.c +++ b/source/config.c @@ -1,14 +1,5 @@ #include "render.h" -#define SOKOL_TRACE_HOOKS -#define SOKOL_IMPL -#define SOKOL_NO_ENTRY -#include "sokol/sokol_time.h" -#include "sokol/sokol_gfx.h" -#include "sokol/sokol_app.h" -#include "sokol/sokol_log.h" -#include "sokol/sokol_glue.h" - #define CUTE_ASEPRITE_IMPLEMENTATION #include "cute_aseprite.h" diff --git a/source/datastream.c b/source/datastream.c index e0553a85..383661a1 100644 --- a/source/datastream.c +++ b/source/datastream.c @@ -10,11 +10,9 @@ #include "cbuf.h" -#include "sokol/sokol_gfx.h" - void datastream_free(JSRuntime *rt,datastream *ds) { - sg_destroy_image(ds->img); +// sg_destroy_image(ds->img); plm_destroy(ds->plm); free(ds); } @@ -29,9 +27,9 @@ static void render_frame(plm_t *mpeg, plm_frame_t *frame, struct datastream *ds) uint8_t rgb[frame->height*frame->width*4]; memset(rgb,255,frame->height*frame->width*4); plm_frame_to_rgba(frame, rgb, frame->width*4); - sg_image_data imgd = {0}; - imgd.subimage[0][0] = SG_RANGE(rgb); - sg_update_image(ds->img, &imgd); +// sg_image_data imgd = {0}; +// imgd.subimage[0][0] = SG_RANGE(rgb); +// sg_update_image(ds->img, &imgd); ds->dirty = true; } @@ -49,14 +47,14 @@ struct datastream *ds_openvideo(void *raw, size_t rawlen) if (!ds->plm) return NULL; - ds->img = sg_make_image(&(sg_image_desc){ +/* ds->img = sg_make_image(&(sg_image_desc){ .width = plm_get_width(ds->plm), .height = plm_get_height(ds->plm), .usage = SG_USAGE_STREAM, .type = SG_IMAGETYPE_2D, .pixel_format = SG_PIXELFORMAT_RGBA8, }); - +*/ plm_set_video_decode_callback(ds->plm, render_frame, ds); return ds; diff --git a/source/datastream.h b/source/datastream.h index b64cb528..d45f0a3d 100644 --- a/source/datastream.h +++ b/source/datastream.h @@ -5,16 +5,10 @@ #include #include -#include "sokol/sokol_gfx.h" - struct soundstream; struct datastream { plm_t *plm; - sg_image img; - sg_image y; - sg_image cr; - sg_image cb; int width; int height; int dirty; diff --git a/source/font.c b/source/font.c index 1ec17ad5..3a13d329 100644 --- a/source/font.c +++ b/source/font.c @@ -16,19 +16,8 @@ struct sFont *use_font; -struct text_vert { - HMM_Vec2 pos; - HMM_Vec2 wh; - HMM_Vec2 uv; - HMM_Vec2 st; - HMM_Vec4 color; -}; - -static struct text_vert *text_buffer; - void font_free(JSRuntime *rt, font *f) { - sg_destroy_image(f->texID); free(f); } @@ -61,7 +50,7 @@ struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) { if (!ttf_buffer) return NULL; - int packsize = 2048; + int packsize = 1024; struct sFont *newfont = calloc(1, sizeof(struct sFont)); newfont->height = height; @@ -90,21 +79,14 @@ struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) { newfont->ascent = ascent*emscale; newfont->descent = descent*emscale; newfont->linegap = linegap*emscale; - newfont->texture = malloc(sizeof(texture)); - newfont->texture->id = sg_make_image(&(sg_image_desc){ - .type = SG_IMAGETYPE_2D, - .width = packsize, - .height = packsize, - .pixel_format = SG_PIXELFORMAT_R8, - .usage = SG_USAGE_IMMUTABLE, - .data.subimage[0][0] = { - .ptr = bitmap, - .size = packsize * packsize - } - }); + newfont->surface = SDL_CreateSurface(packsize,packsize, SDL_PIXELFORMAT_RGBA32); + if (!newfont->surface) printf("SDL ERROR: %s\n", SDL_GetError()); + for (int i = 0; i < packsize; i++) + for (int j = 0; j < packsize; j++) + if (!SDL_WriteSurfacePixel(newfont->surface, j, i, 255,255,255,bitmap[i*packsize+j])) + printf("SDLERROR: %s\n", SDL_GetError()); - newfont->texture->width = packsize; - newfont->texture->height = packsize; + printf("FONT SURFACE IS %p\n", newfont->surface); for (unsigned char c = 32; c < 127; c++) { stbtt_packedchar glyph = glyphs[c - 32]; @@ -131,8 +113,8 @@ struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) { return newfont; } -int text_flush(sg_buffer *buf) { - if (arrlen(text_buffer) == 0) return 0; +int text_flush() { +/* if (arrlen(text_buffer) == 0) return 0; sg_range verts; verts.ptr = text_buffer; @@ -151,24 +133,52 @@ int text_flush(sg_buffer *buf) { int n = arrlen(text_buffer); arrsetlen(text_buffer, 0); return n; +*/ } -void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) { +void sdrawCharacter(struct text_vert **buffer, struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) { struct text_vert vert; vert.pos.x = cursor.X + c.leftbearing; vert.pos.y = cursor.Y + c.topbearing; - vert.wh = c.size; +// vert.wh = c.size; // if (vert.pos.x > frame.l || vert.pos.y > frame.t || (vert.pos.y + vert.wh.y) < frame.b || (vert.pos.x + vert.wh.x) < frame.l) return; vert.uv.x = c.rect.x; vert.uv.y = c.rect.y; - vert.st.x = c.rect.w; - vert.st.y = c.rect.h; +// vert.st.x = c.rect.w; +// vert.st.y = c.rect.h; rgba2floats(vert.color.e, color); - arrput(text_buffer, vert); + arrput(*buffer, vert); +} + +void draw_char_verts(struct text_vert **buffer, struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) +{ + // Adds four verts: bottom left, bottom right, top left, top right + text_vert bl; + bl.pos.x = cursor.X + c.leftbearing; + bl.pos.y = cursor.Y + c.topbearing; + bl.uv.x = c.rect.x; + bl.uv.y = c.rect.y+c.rect.h; + rgba2floats(bl.color.e, color); + arrput(*buffer, bl); + + text_vert br = bl; + br.pos.x += c.size.x; + br.uv.x += c.rect.w; + arrput(*buffer, br); + + text_vert ul = bl; + ul.pos.y -= c.size.y; + ul.uv.y = c.rect.y; + arrput(*buffer, ul); + + text_vert ur = ul; + ur.pos.x += c.size.x; + ur.uv.x += c.rect.w; + arrput(*buffer, ur); } const char *esc_color(const char *c, struct rgba *color, struct rgba defc) @@ -229,7 +239,8 @@ HMM_Vec2 measure_text(const char *text, font *f, float size, float letterSpacing } /* pos given in screen coordinates */ -void renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgba color, float wrap) { +struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgba color, float wrap) { + text_vert *buffer = NULL; int len = strlen(text); HMM_Vec2 cursor = pos; @@ -243,11 +254,11 @@ void renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgb continue; } - sdrawCharacter(f->Characters[*c], cursor, scale, color); + draw_char_verts(&buffer, f->Characters[*c], cursor, scale, color); cursor.x += f->Characters[*c].Advance; } - return; - + return buffer; +/* const char *line, *wordstart, *drawstart; line = drawstart = text; @@ -291,5 +302,5 @@ void renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgb wordstart++; } } - } + }*/ } diff --git a/source/font.h b/source/font.h index 1a7e0186..d09d5a71 100644 --- a/source/font.h +++ b/source/font.h @@ -1,11 +1,11 @@ #ifndef FONT_H #define FONT_H -#include "sokol/sokol_gfx.h" #include "render.h" #include "HandmadeMath.h" #include #include "texture.h" +#include typedef enum { LEFT, @@ -14,11 +14,17 @@ typedef enum { JUSTIFY } ALIGN; +struct text_vert { + HMM_Vec2 pos; + HMM_Vec2 uv; + HMM_Vec4 color; +}; + +typedef struct text_vert text_vert; + struct shader; struct window; -extern sg_buffer text_ssbo; - /// Holds all state information relevant to a character as loaded using FreeType struct Character { float Advance; // Horizontal offset to advance to next glyph @@ -28,14 +34,14 @@ struct Character { HMM_Vec2 size; // The pixel size of this letter }; +// text data struct sFont { uint32_t height; /* in pixels */ float ascent; // pixels float descent; // pixels float linegap; //pixels struct Character Characters[256]; - sg_image texID; - texture *texture; + SDL_Surface *surface; }; typedef struct sFont font; @@ -44,11 +50,10 @@ typedef struct Character glyph; void font_free(JSRuntime *rt,font *f); struct sFont *MakeFont(void *data, size_t len, int height); -void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color); -void renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgba color, float wrap); +struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgba color, float wrap); HMM_Vec2 measure_text(const char *text, font *f, float scale, float letterSpacing, float wrap); // Flushes all letters from renderText calls into the provided buffer -int text_flush(sg_buffer *buf); +int text_flush(); #endif diff --git a/source/gif_load.h b/source/gif_load.h deleted file mode 100644 index 6c76c106..00000000 --- a/source/gif_load.h +++ /dev/null @@ -1,299 +0,0 @@ -#ifndef GIF_LOAD_H -#define GIF_LOAD_H - -/** gif_load: A slim, fast and header-only GIF loader written in C. - Original author: hidefromkgb (hidefromkgb@gmail.com) - _________________________________________________________________________ - - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - _________________________________________________________________________ -**/ - -#ifdef __cplusplus -extern "C" { -#endif -#include /** imports uint8_t, uint16_t and uint32_t **/ -#ifndef GIF_MGET - #include - #define GIF_MGET(m,s,a,c) m = (uint8_t*)realloc((c)? 0 : m, (c)? s : 0UL); -#endif -#ifndef GIF_BIGE - #define GIF_BIGE 0 -#endif -#ifndef GIF_EXTR - #define GIF_EXTR static -#endif -#define _GIF_SWAP(h) ((GIF_BIGE)? ((uint16_t)(h << 8) | (h >> 8)) : h) - -#pragma pack(push, 1) -struct GIF_WHDR { /** ======== frame writer info: ======== **/ - long xdim, ydim, clrs, /** global dimensions, palette size **/ - bkgd, tran, /** background index, transparent index **/ - intr, mode, /** interlace flag, frame blending mode **/ - frxd, fryd, frxo, fryo, /** current frame dimensions and offset **/ - time, ifrm, nfrm; /** delay, frame number, frame count **/ - uint8_t *bptr; /** frame pixel indices or metadata **/ - struct { /** [==== GIF RGB palette element: ====] **/ - uint8_t R, G, B; /** [color values - red, green, blue ] **/ - } *cpal; /** current palette **/ -}; -#pragma pack(pop) - -enum {GIF_NONE = 0, GIF_CURR = 1, GIF_BKGD = 2, GIF_PREV = 3}; - -/** [ internal function, do not use ] **/ -static long _GIF_SkipChunk(uint8_t **buff, long size) { - long skip; - - for (skip = 2, ++size, ++(*buff); ((size -= skip) > 0) && (skip > 1); - *buff += (skip = 1 + **buff)); - return size; -} - -/** [ internal function, do not use ] **/ -static long _GIF_LoadHeader(unsigned gflg, uint8_t **buff, void **rpal, - unsigned fflg, long *size, long flen) { - if (flen && (!(*buff += flen) || ((*size -= flen) <= 0))) - return -2; /** v--[ 0x80: "palette is present" flag ]--, **/ - if (flen && (fflg & 0x80)) { /** local palette has priority | **/ - *rpal = *buff; /** [ 3L: 3 uint8_t color channels ]--, | **/ - *buff += (flen = 2 << (fflg & 7)) * 3L; /** <--| | **/ - return ((*size -= flen * 3L) > 0)? flen : -1; /** <--' | **/ - } /** no local palette found, checking for the global one | **/ - return (gflg & 0x80)? (2 << (gflg & 7)) : 0; /** <-----' **/ -} - -/** [ internal function, do not use ] **/ -static long _GIF_LoadFrame(uint8_t **buff, long *size, - uint8_t *bptr, uint8_t *blen) { - typedef uint16_t GIF_H; - const long GIF_HLEN = sizeof(GIF_H), /** to rid the scope of sizeof **/ - GIF_CLEN = 1 << 12; /** code table length: 4096 items **/ - GIF_H accu, mask; /** bit accumulator / bit mask **/ - long ctbl, iter, /** last code table index / index string iterator **/ - prev, curr, /** codes from the stream: previous / current **/ - ctsz, ccsz, /** code table bit sizes: min LZW / current **/ - bseq, bszc; /** counters: block sequence / bit size **/ - uint32_t *code = (uint32_t*)bptr - GIF_CLEN; /** code table pointer **/ - - /** preparing initial values **/ - if ((--(*size) <= GIF_HLEN) || !*++(*buff)) - return -4; /** unexpected end of the stream: insufficient size **/ - mask = (GIF_H)((1 << (ccsz = (ctsz = *(*buff - 1)) + 1)) - 1); - if ((ctsz < 2) || (ctsz > 8)) - return -3; /** min LZW size is out of its nominal [2; 8] bounds **/ - if ((ctbl = (1L << ctsz)) != (mask & _GIF_SWAP(*(GIF_H*)(*buff + 1)))) - return -2; /** initial code is not equal to min LZW size **/ - for (curr = ++ctbl; curr; code[--curr] = 0); /** actual color codes **/ - - /** getting codes from stream (--size makes up for end-of-stream mark) **/ - for (--(*size), bszc = -ccsz, prev = curr = 0; - ((*size -= (bseq = *(*buff)++) + 1) >= 0) && bseq; *buff += bseq) - for (; bseq > 0; bseq -= GIF_HLEN, *buff += GIF_HLEN) - for (accu = (GIF_H)(_GIF_SWAP(*(GIF_H*)*buff) - & ((bseq < GIF_HLEN)? ((1U << (8 * bseq)) - 1U) : ~0U)), - curr |= accu << (ccsz + bszc), accu = (GIF_H)(accu >> -bszc), - bszc += 8 * ((bseq < GIF_HLEN)? bseq : GIF_HLEN); - bszc >= 0; bszc -= ccsz, prev = curr, curr = accu, - accu = (GIF_H)(accu >> ccsz)) - if (((curr &= mask) & ~1L) == (1L << ctsz)) { - if (~(ctbl = curr + 1) & 1) /** end-of-data code (ED). **/ - /** -1: no end-of-stream mark after ED; 1: decoded **/ - return (*((*buff += bseq + 1) - 1))? -1 : 1; - mask = (GIF_H)((1 << (ccsz = ctsz + 1)) - 1); - } /** ^- table drop code (TD). TD = 1 << ctsz, ED = TD + 1 **/ - else { /** single-pixel (SP) or multi-pixel (MP) code. **/ - if (ctbl < GIF_CLEN) { /** is the code table full? **/ - if ((ctbl == mask) && (ctbl < GIF_CLEN - 1)) { - mask = (GIF_H)(mask + mask + 1); - ccsz++; /** yes; extending **/ - } /** prev = TD? => curr < ctbl = prev **/ - code[ctbl] = (uint32_t)prev + (code[prev] & 0xFFF000); - } /** appending SP / MP decoded pixels to the frame **/ - prev = (long)code[iter = (ctbl > curr)? curr : prev]; - if ((bptr += (prev = (prev >> 12) & 0xFFF)) > blen) - continue; /** skipping pixels above frame capacity **/ - for (prev++; (iter &= 0xFFF) >> ctsz; - *bptr-- = (uint8_t)((iter = (long)code[iter]) >> 24)); - (bptr += prev)[-prev] = (uint8_t)iter; - if (ctbl < GIF_CLEN) { /** appending the code table **/ - if (ctbl == curr) - *bptr++ = (uint8_t)iter; - else if (ctbl < curr) - return -5; /** wrong code in the stream **/ - code[ctbl++] += ((uint32_t)iter << 24) + 0x1000; - } - } /** 0: no ED before end-of-stream mark; -4: see above **/ - return (++(*size) >= 0)? 0 : -4; /** ^- N.B.: 0 error is recoverable **/ -} - -/** _________________________________________________________________________ - The main loading function. Returns the total number of frames if the data - includes proper GIF ending, and otherwise it returns the number of frames - loaded per current call, multiplied by -1. So, the data may be incomplete - and in this case the function can be called again when more data arrives, - just remember to keep SKIP up to date. - _________________________________________________________________________ - DATA: raw data chunk, may be partial - SIZE: size of the data chunk that`s currently present - GWFR: frame writer function, MANDATORY - EAMF: metadata reader function, set to 0 if not needed - ANIM: implementation-specific data (e.g. a structure or a pointer to it) - SKIP: number of frames to skip before resuming - **/ -GIF_EXTR long GIF_Load(void *data, long size, - void (*gwfr)(void*, struct GIF_WHDR*), - void (*eamf)(void*, struct GIF_WHDR*), - void *anim, long skip) { - const long GIF_BLEN = (1 << 12) * sizeof(uint32_t); - const uint8_t GIF_EHDM = 0x21, /** extension header mark **/ - GIF_FHDM = 0x2C, /** frame header mark **/ - GIF_EOFM = 0x3B, /** end-of-file mark **/ - GIF_EGCM = 0xF9, /** extension: graphics control mark **/ - GIF_EAMM = 0xFF; /** extension: app metadata mark **/ - #pragma pack(push, 1) - struct GIF_GHDR { /** ========== GLOBAL GIF HEADER: ========== **/ - uint8_t head[6]; /** 'GIF87a' / 'GIF89a' header signature **/ - uint16_t xdim, ydim; /** total image width, total image height **/ - uint8_t flgs; /** FLAGS: - GlobalPlt bit 7 1: global palette exists - 0: local in each frame - ClrRes bit 6-4 bits/channel = ClrRes+1 - [reserved] bit 3 0 - PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits - **/ - uint8_t bkgd, aspr; /** background color index, aspect ratio **/ - } *ghdr = (struct GIF_GHDR*)data; - struct GIF_FHDR { /** ======= GIF FRAME MASTER HEADER: ======= **/ - uint16_t frxo, fryo; /** offset of this frame in a "full" image **/ - uint16_t frxd, fryd; /** frame width, frame height **/ - uint8_t flgs; /** FLAGS: - LocalPlt bit 7 1: local palette exists - 0: global is used - Interlaced bit 6 1: interlaced frame - 0: non-interlaced frame - Sorted bit 5 usually 0 - [reserved] bit 4-3 [undefined] - PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits - **/ - } *fhdr; - struct GIF_EGCH { /** ==== [EXT] GRAPHICS CONTROL HEADER: ==== **/ - uint8_t flgs; /** FLAGS: - [reserved] bit 7-5 [undefined] - BlendMode bit 4-2 000: not set; static GIF - 001: leave result as is - 010: restore background - 011: restore previous - 1--: [undefined] - UserInput bit 1 1: show frame till input - 0: default; ~99% of GIFs - TransColor bit 0 1: got transparent color - 0: frame is fully opaque - **/ - uint16_t time; /** delay in GIF time units; 1 unit = 10 ms **/ - uint8_t tran; /** transparent color index **/ - } *egch = 0; - #pragma pack(pop) - struct GIF_WHDR wtmp, whdr = {0}; - long desc, blen; - uint8_t *buff; - - /** checking if the stream is not empty and has a 'GIF8[79]a' signature, - the data has sufficient size and frameskip value is non-negative **/ - if (!ghdr || (size <= (long)sizeof(*ghdr)) || (*(buff = ghdr->head) != 71) - || (buff[1] != 73) || (buff[2] != 70) || (buff[3] != 56) || (skip < 0) - || ((buff[4] != 55) && (buff[4] != 57)) || (buff[5] != 97) || !gwfr) - return 0; - - buff = (uint8_t*)(ghdr + 1) /** skipping the global header and palette **/ - + _GIF_LoadHeader(ghdr->flgs, 0, 0, 0, 0, 0L) * 3L; - if ((size -= buff - (uint8_t*)ghdr) <= 0) - return 0; - - whdr.xdim = _GIF_SWAP(ghdr->xdim); - whdr.ydim = _GIF_SWAP(ghdr->ydim); - for (whdr.bptr = buff, whdr.bkgd = ghdr->bkgd, blen = --size; - (blen >= 0) && ((desc = *whdr.bptr++) != GIF_EOFM); /** sic: '>= 0' **/ - blen = _GIF_SkipChunk(&whdr.bptr, blen) - 1) /** count all frames **/ - if (desc == GIF_FHDM) { - fhdr = (struct GIF_FHDR*)whdr.bptr; - if (_GIF_LoadHeader(ghdr->flgs, &whdr.bptr, (void**)&whdr.cpal, - fhdr->flgs, &blen, sizeof(*fhdr)) <= 0) - break; - whdr.frxd = _GIF_SWAP(fhdr->frxd); - whdr.fryd = _GIF_SWAP(fhdr->fryd); - whdr.frxo = (whdr.frxd > whdr.frxo)? whdr.frxd : whdr.frxo; - whdr.fryo = (whdr.fryd > whdr.fryo)? whdr.fryd : whdr.fryo; - whdr.ifrm++; - } - blen = whdr.frxo * whdr.fryo * (long)sizeof(*whdr.bptr); - GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 1) - whdr.nfrm = (desc != GIF_EOFM)? -whdr.ifrm : whdr.ifrm; - for (whdr.bptr += GIF_BLEN, whdr.ifrm = -1; blen /** load all frames **/ - && (skip < ((whdr.nfrm < 0)? -whdr.nfrm : whdr.nfrm)) && (size >= 0); - size = (desc != GIF_EOFM)? ((desc != GIF_FHDM) || (skip > whdr.ifrm))? - _GIF_SkipChunk(&buff, size) - 1 : size - 1 : -1) - if ((desc = *buff++) == GIF_FHDM) { /** found a frame **/ - whdr.intr = !!((fhdr = (struct GIF_FHDR*)buff)->flgs & 0x40); - *(void**)&whdr.cpal = (void*)(ghdr + 1); /** interlaced? -^ **/ - whdr.clrs = _GIF_LoadHeader(ghdr->flgs, &buff, (void**)&whdr.cpal, - fhdr->flgs, &size, sizeof(*fhdr)); - if ((skip <= ++whdr.ifrm) && ((whdr.clrs <= 0) - || (_GIF_LoadFrame(&buff, &size, - whdr.bptr, whdr.bptr + blen) < 0))) - size = -(whdr.ifrm--) - 1; /** failed to load the frame **/ - else if (skip <= whdr.ifrm) { - whdr.frxd = _GIF_SWAP(fhdr->frxd); - whdr.fryd = _GIF_SWAP(fhdr->fryd); - whdr.frxo = _GIF_SWAP(fhdr->frxo); - whdr.fryo = _GIF_SWAP(fhdr->fryo); - whdr.time = (egch)? _GIF_SWAP(egch->time) : 0; - whdr.tran = (egch && (egch->flgs & 0x01))? egch->tran : -1; - whdr.time = (egch && (egch->flgs & 0x02))? -whdr.time - 1 - : whdr.time; - whdr.mode = (egch && !(egch->flgs & 0x10))? - (egch->flgs & 0x0C) >> 2 : GIF_NONE; - egch = 0; - wtmp = whdr; - gwfr(anim, &wtmp); /** passing the frame to the caller **/ - } - } - else if (desc == GIF_EHDM) { /** found an extension **/ - if (*buff == GIF_EGCM) /** graphics control ext. **/ - egch = (struct GIF_EGCH*)(buff + 1 + 1); - else if ((*buff == GIF_EAMM) && eamf) { /** app metadata ext. **/ - wtmp = whdr; - wtmp.bptr = buff + 1 + 1; /** just passing the raw chunk **/ - eamf(anim, &wtmp); - } - } - whdr.bptr -= GIF_BLEN; /** for excess pixel codes ----v (here & above) **/ - GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 0) - return (whdr.nfrm < 0)? (skip - whdr.ifrm - 1) : (whdr.ifrm + 1); -} - -#undef _GIF_SWAP -#ifdef __cplusplus -} -#endif -#endif /** GIF_LOAD_H **/ \ No newline at end of file diff --git a/source/jsffi.c b/source/jsffi.c index 6ad1d834..145eb454 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -10,8 +10,6 @@ #include "spline.h" #include "yugine.h" #include -#include -#include #include #include #include @@ -23,14 +21,59 @@ #include "HandmadeMath.h" #include "par/par_streamlines.h" #include "par/par_shapes.h" -#include "sokol_glue.h" -#include "sokol_gfx.h" -#include "sokol_log.h" #include #include "timer.h" #include -#include "tinydir.h" -#include "cute_aseprite.h" +#include "cute_aseprite.h" + +#include "physfs.h" + +#include +#include +#include + +#include + +static JSAtom width_atom; +static JSAtom height_atom; +static JSAtom x_atom; +static JSAtom y_atom; +static JSAtom anchor_x_atom; +static JSAtom anchor_y_atom; +static JSAtom pos_atom; +static JSAtom uv_atom; +static JSAtom color_atom; +static JSAtom indices_atom; +static JSAtom vertices_atom; +static JSAtom dst_atom; +static JSAtom src_atom; +static JSAtom count_atom; + +static inline size_t typed_array_bytes(JSTypedArrayEnum type) { + switch(type) { + case JS_TYPED_ARRAY_UINT8C: + case JS_TYPED_ARRAY_INT8: + case JS_TYPED_ARRAY_UINT8: + return 1; + + case JS_TYPED_ARRAY_INT16: + case JS_TYPED_ARRAY_UINT16: + return 2; + + case JS_TYPED_ARRAY_INT32: + case JS_TYPED_ARRAY_UINT32: + case JS_TYPED_ARRAY_FLOAT32: + return 4; + + case JS_TYPED_ARRAY_BIG_INT64: + case JS_TYPED_ARRAY_BIG_UINT64: + case JS_TYPED_ARRAY_FLOAT64: + return 8; + + default: + return 0; // Return 0 for unknown types + } +} #define JS_GETNUM(JS,VAL,I,TO,TYPE) { \ JSValue val = JS_GetPropertyUint32(JS,VAL,I); \ @@ -60,6 +103,9 @@ double js_getnum_uint32(JSContext *js, JSValue v, unsigned int i) return ret; } +static HMM_Vec2 campos = (HMM_Vec2){0,0}; +static HMM_Vec2 logical = {0}; + double js_getnum_str(JSContext *js, JSValue v, const char *str) { JSValue val = JS_GetPropertyStr(js,v,str); @@ -68,11 +114,24 @@ double js_getnum_str(JSContext *js, JSValue v, const char *str) return ret; } +double js_getnum(JSContext *js, JSValue v, JSAtom prop) +{ + JSValue val = JS_GetProperty(js,v,prop); + double ret = js2number(js,val); + JS_FreeValue(js,val); + return ret; +} + #define JS_GETPROPSTR(JS, VALUE, TARGET, STR, TYPE) {\ JSValue __v = JS_GetPropertyStr(JS,VALUE,#STR); \ TARGET.STR = js2##TYPE(JS, __v); \ JS_FreeValue(JS,__v); }\ +#define JS_GETPROP(JS, VALUE, TARGET, PROP, TYPE) {\ +JSValue __v = JS_GetProperty(JS,VALUE,PROP); \ +TARGET.STR = js2##TYPE(JS, __v); \ +JS_FreeValue(JS,__v); }\ + JSValue js_getpropertystr(JSContext *js, JSValue v, const char *str) { JSValue ret = JS_GetPropertyStr(js, v, str); @@ -80,6 +139,43 @@ JSValue js_getpropertystr(JSContext *js, JSValue v, const char *str) return ret; } +JSValue js_getproperty(JSContext *js, JSValue v, JSAtom atom) +{ + JSValue ret = JS_GetProperty(js, v, atom); + JS_FreeValue(js,ret); + return ret; +} + +void free_gpu_buffer(JSRuntime *rt, void *opaque, void *ptr) +{ + free(ptr); +} + +JSValue make_gpu_buffer(JSContext *js, void *data, size_t size, int type, int elements, int copy) +{ + JSValue tstack[3]; + tstack[1] = JS_UNDEFINED; + tstack[2] = JS_UNDEFINED; + if (copy) + tstack[0] = JS_NewArrayBufferCopy(js,data,size);//, make_gpu_buffer, NULL, 1); + else + tstack[0] = JS_NewArrayBuffer(js,data,size,free_gpu_buffer, NULL, 0); + JSValue ret = JS_NewTypedArray(js, 3, tstack, type); + JS_SetPropertyStr(js,ret,"stride", number2js(js,typed_array_bytes(type)*elements)); + JS_FreeValue(js,tstack[0]); + return ret; +} + +void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride) +{ + size_t o, len, bytes, size; + JSValue buf = JS_GetTypedArrayBuffer(js, argv, &o, &len, &bytes); + void *data = JS_GetArrayBuffer(js, &size, buf); + JS_FreeValue(js,buf); + *stride = js_getnum_str(js, argv, "stride"); + return data; +} + static inline JSValue bool2js(JSContext *js, int b) { return JS_NewBool(js,b); } static inline int js2bool(JSContext *js, JSValue v) { return JS_ToBool(js,v); } @@ -121,92 +217,6 @@ JSValue vec22js(JSContext *js,HMM_Vec2 v) return array; } -const char *sapp_str[] = { - "invalid", - "key_down", - "key_up", - "char", - "mouse_down", - "mouse_up", - "mouse_scroll", - "mouse_move", - "mouse_enter", - "mouse_leave", - "touches_began", - "touches_moved", - "touches_ended", - "touches_cancelled", - "resized", - "iconified", - "restored", - "focused", - "unfocused", - "suspended", - "resumed", - "quit_requested", - "clipboard_pasted", - "files_dropped" -}; -JSValue sapp_event2js(JSContext *js, sapp_event *e) -{ - JSValue event = JS_NewObject(js); - JS_SetPropertyStr(js, event, "frame_count", JS_NewInt64(js, e->frame_count)); - JS_SetPropertyStr(js, event, "type", JS_NewString(js, sapp_str[e->type])); - JS_SetPropertyStr(js,event,"mouse", vec22js(js, (HMM_Vec2){e->mouse_x,e->mouse_y})); - JS_SetPropertyStr(js,event,"mouse_d", vec22js(js, (HMM_Vec2){e->mouse_dx,e->mouse_dy})); - JS_SetPropertyStr(js,event, "window_size", vec22js(js, (HMM_Vec2){e->window_width,e->window_height})); - JS_SetPropertyStr(js,event, "framebuffer", vec22js(js,(HMM_Vec2){e->framebuffer_width,e->framebuffer_height})); - JSValue files = JS_UNDEFINED; - - switch(e->type) { - case SAPP_EVENTTYPE_MOUSE_SCROLL: - JS_SetPropertyStr(js, event, "scroll", vec22js(js, (HMM_Vec2){e->scroll_x,e->scroll_y})); - JS_SetPropertyStr(js, event, "modifiers", JS_NewBool(js, e->modifiers)); - break; - case SAPP_EVENTTYPE_KEY_UP: - case SAPP_EVENTTYPE_KEY_DOWN: - JS_SetPropertyStr(js, event, "key_code", JS_NewInt64(js, e->key_code)); - JS_SetPropertyStr(js, event, "char_code", JS_NewUint32(js, e->char_code)); - JS_SetPropertyStr(js, event, "key_repeat", JS_NewBool(js, e->key_repeat)); - JS_SetPropertyStr(js, event, "modifiers", JS_NewBool(js, e->modifiers)); - break; - case SAPP_EVENTTYPE_CHAR: - JS_SetPropertyStr(js, event, "char_code", JS_NewUint32(js, e->char_code)); - JS_SetPropertyStr(js, event, "key_repeat", JS_NewBool(js, e->key_repeat)); - JS_SetPropertyStr(js, event, "modifiers", JS_NewBool(js, e->modifiers)); - break; - case SAPP_EVENTTYPE_TOUCHES_BEGAN: - case SAPP_EVENTTYPE_TOUCHES_MOVED: - case SAPP_EVENTTYPE_TOUCHES_ENDED: - JS_SetPropertyStr(js, event, "num_touches", JS_NewUint32(js, e->num_touches)); - JSValue touches = JS_NewObject(js); - for (int i = 0; i < e->num_touches; i++) { - JSValue touch = JS_NewObject(js); - JS_SetPropertyStr(js, touch,"id", JS_NewInt64(js,e->touches[i].identifier)); - JS_SetPropertyStr(js, touch, "pos", vec22js(js, (HMM_Vec2){e->touches[i].pos_x, e->touches[i].pos_y})); - JS_SetPropertyStr(js,touch,"changed", JS_NewBool(js,e->touches[i].changed)); - JS_SetPropertyUint32(js,touches,i, touch); - } - JS_SetPropertyStr(js,event,"touches",touches); - break; - case SAPP_EVENTTYPE_MOUSE_UP: - case SAPP_EVENTTYPE_MOUSE_DOWN: - JS_SetPropertyStr(js, event, "mouse_button", JS_NewUint32(js, e->mouse_button)); - JS_SetPropertyStr(js, event, "modifiers", JS_NewBool(js, e->modifiers)); - break; - case SAPP_EVENTTYPE_FILES_DROPPED: - files = JS_NewObject(js); - for (int i = 0; i < sapp_get_num_dropped_files(); i++) - JS_SetPropertyUint32(js,files,i,JS_NewString(js,sapp_get_dropped_file_path(0))); - JS_SetPropertyStr(js,event,"files",files); - break; - case SAPP_EVENTTYPE_CLIPBOARD_PASTED: - JS_SetPropertyStr(js,event,"clipboard",JS_NewString(js,sapp_get_clipboard_string())); - break; - } - return event; -} - char *js2strdup(JSContext *js, JSValue v) { const char *str = JS_ToCString(js, v); char *ret = strdup(str); @@ -214,18 +224,6 @@ char *js2strdup(JSContext *js, JSValue v) { return ret; } -void sg_buffer_free(JSRuntime *rt,sg_buffer *b) -{ - sg_destroy_buffer(*b); - free(b); -} - -void sg_pipeline_free(JSRuntime *rt,sg_pipeline *p) -{ - sg_destroy_pipeline(*p); - free(p); -} - void skin_free(JSRuntime *rt,skin *sk) { arrfree(sk->invbind); free(sk); @@ -233,16 +231,39 @@ void skin_free(JSRuntime *rt,skin *sk) { #include "qjs_macros.h" +void SDL_Window_free(JSRuntime *rt, SDL_Window *w) +{ + SDL_DestroyWindow(w); +} + +void SDL_Renderer_free(JSRuntime *rt, SDL_Renderer *r) +{ + SDL_DestroyRenderer(r); +} + +void SDL_Texture_free(JSRuntime *rt, SDL_Texture *t){ + TracyCFreeN(t, "vram"); + SDL_DestroyTexture(t); +} +void SDL_Surface_free(JSRuntime *rt, SDL_Surface *s) { + if (s->flags & SDL_SURFACE_PREALLOCATED) + free(s->pixels); + TracyCFreeN(s,"texture memory"); + SDL_DestroySurface(s); +} + QJSCLASS(transform) QJSCLASS(texture) QJSCLASS(font) //QJSCLASS(warp_gravity) //QJSCLASS(warp_damp) -QJSCLASS(sg_buffer) -QJSCLASS(sg_pipeline) QJSCLASS(datastream) QJSCLASS(timer) QJSCLASS(skin) +QJSCLASS(SDL_Window) +QJSCLASS(SDL_Renderer) +QJSCLASS(SDL_Texture, TracyCAllocN(n, n->w*n->h*4, "vram");) +QJSCLASS(SDL_Surface, TracyCAllocN(n, n->pitch*n->h, "texture memory");) static inline HMM_Mat4 js2transform_mat(JSContext *js, JSValue v) { @@ -265,6 +286,30 @@ int js_arrlen(JSContext *js,JSValue v) { return len; } +void *get_typed_buffer(JSContext *js, JSValue argv, size_t *len) +{ + size_t o,bytes,size; + JSValue buf = JS_GetTypedArrayBuffer(js,argv,&o,len,&bytes); + void *data = JS_GetArrayBuffer(js,&size,buf); + JS_FreeValue(js,buf); + return data; +} + +float *js2floatarray(JSContext *js, JSValue v) { + JSClassID class = JS_GetClassID(v); + if (class == JS_CLASS_FLOAT32_ARRAY) { + printf("FAST PATH\n"); + size_t len; + return get_typed_buffer(js,v, &len); + } +// switch(p->class_id){} + int len = js_arrlen(js,v); + float *array = malloc(sizeof(float)*len); + for (int i = 0; i < len; i++) + array[i] = js_getnum_uint32(js,v,i); + return array; +} + JSValue angle2js(JSContext *js,double g) { return number2js(js,g*HMM_RadToTurn); } @@ -317,6 +362,24 @@ HMM_Vec3 js2vec3(JSContext *js,JSValue v) return v3; } +float *js2floats(JSContext *js, JSValue v, size_t *len) +{ + *len = js_arrlen(js,v); + float *arr = malloc(sizeof(float)* *len); + for (int i = 0; i < *len; i++) + arr[i] = js_getnum_uint32(js,v,i); + return arr; +} + +double *js2doubles(JSContext *js, JSValue v, size_t *len) +{ + *len = js_arrlen(js,v); + double *arr = malloc(sizeof(double)* *len); + for (int i = 0; i < *len; i++) + arr[i] = js_getnum_uint32(js,v,i); + return arr; +} + HMM_Vec3 js2vec3f(JSContext *js, JSValue v) { HMM_Vec3 vec; @@ -431,14 +494,20 @@ int js_print_exception(JSContext *js, JSValue v) return 0; } -struct rect js2rect(JSContext *js,JSValue v) { - struct rect rect; - JS_GETPROPSTR(js,v,rect,x,number) - JS_GETPROPSTR(js,v,rect,y,number) - rect.w = js_getnum_str(js,v,"width"); - rect.h = js_getnum_str(js,v,"height"); - float anchor_x = js_getnum_str(js,v, "anchor_x"); - float anchor_y = js_getnum_str(js,v, "anchor_y"); +typedef SDL_FRect rect; + +rect js2rect(JSContext *js,JSValue v) { + rect rect; + rect.w = js_getnum(js,v,width_atom); + rect.h = js_getnum(js,v,height_atom); + JSValue xv = JS_GetProperty(js,v,x_atom); + rect.x = js2number(js,xv); + JS_FreeValue(js,xv); + JSValue yv = JS_GetProperty(js,v,y_atom); + rect.y = js2number(js,yv); + JS_FreeValue(js,yv); + float anchor_x = js_getnum(js,v, anchor_x_atom); + float anchor_y = js_getnum(js,v, anchor_y_atom); rect.y -= anchor_y*rect.h; rect.x -= anchor_x*rect.w; @@ -446,12 +515,12 @@ struct rect js2rect(JSContext *js,JSValue v) { return rect; } -JSValue rect2js(JSContext *js,struct rect rect) { +JSValue rect2js(JSContext *js,rect rect) { JSValue obj = JS_NewObject(js); - JS_SetPropertyStr(js, obj, "x", number2js(js,rect.x)); - JS_SetPropertyStr(js, obj, "y", number2js(js,rect.y)); - JS_SetPropertyStr(js, obj, "width", number2js(js,rect.w)); - JS_SetPropertyStr(js, obj, "height", number2js(js,rect.h)); + JS_SetProperty(js, obj, x_atom, number2js(js,rect.x)); + JS_SetProperty(js, obj, y_atom, number2js(js,rect.y)); + JS_SetProperty(js, obj, width_atom, number2js(js,rect.w)); + JS_SetProperty(js, obj, height_atom, number2js(js,rect.h)); return obj; } @@ -555,99 +624,6 @@ static const JSCFunctionListEntry js_warp_damp_funcs [] = { CGETSET_ADD(warp_damp, damp) }; */ -sg_bindings js2bind(JSContext *js,JSValue v) -{ - sg_bindings bind = {0}; - JSValue attrib = JS_GetPropertyStr(js,v, "attrib"); - int len = js_arrlen(js,attrib); - - for (int i = 0; i < len; i++) { - JSValue v = JS_GetPropertyUint32(js,attrib,i); - bind.vertex_buffers[i] = *js2sg_buffer(js, v); - JS_FreeValue(js,v); - } - JS_FreeValue(js,attrib); - - JSValue index = JS_GetPropertyStr(js,v, "index"); - if (!JS_IsUndefined(index)) { - bind.index_buffer = *js2sg_buffer(js, index); - JS_FreeValue(js,index); - } - - JSValue imgs = JS_GetPropertyStr(js,v, "images"); - JSValue samplers = JS_GetPropertyStr(js,v, "samplers"); - len = js_arrlen(js,imgs); - for (int i = 0; i < len; i++) { - JSValue img =JS_GetPropertyUint32(js,imgs,i); - bind.fs.images[i] = js2texture(js, img)->id; - JS_FreeValue(js,img); - JSValue sampler = JS_GetPropertyUint32(js,samplers,i); - int use_std = JS_ToBool(js,sampler); - JS_FreeValue(js,sampler); - bind.fs.samplers[i] = use_std ? std_sampler : tex_sampler; - } - JS_FreeValue(js,imgs); - JS_FreeValue(js,samplers); - - JSValue ssbo = JS_GetPropertyStr(js,v, "ssbo"); - len = js_arrlen(js,ssbo); - for (int i = 0; i < len; i++) { - JSValue v = JS_GetPropertyUint32(js,ssbo,i); - bind.vs.storage_buffers[i] = *js2sg_buffer(js, v); - JS_FreeValue(js,v); - } - JS_FreeValue(js,ssbo); - - return bind; -} - -JSC_CCALL(render_flushtext, - sg_buffer *buf = js2sg_buffer(js, argv[0]); - int amt = text_flush(buf); - return number2js(js,amt); -) - -JSC_CCALL(render_make_textssbo, - sg_buffer *b = malloc(sizeof(*b)); - *b = sg_make_buffer(&(sg_buffer_desc){ - .type = SG_BUFFERTYPE_STORAGEBUFFER, - .size = 4, - .usage = SG_USAGE_STREAM - }); - return sg_buffer2js(js, b); -) - -JSC_CCALL(render_pass, - -) - -JSC_CCALL(render_glue_pass, - sg_begin_pass(&(sg_pass){ - .swapchain = sglue_swapchain(), - .action = (sg_pass_action){ - .colors[0] = { - .load_action = SG_LOADACTION_CLEAR, - .clear_value = (sg_color){0,0,0,1} - }, - .stencil = { .clear_value = 1 - } - } - }); -) - -// Set the portion of the window to be rendered to -JSC_CCALL(render_viewport, - rect view = js2rect(js,argv[0]); - sg_apply_viewportf(view.x, view.y,view.w,view.h, JS_ToBool(js,argv[1])); -) - -JSC_CCALL(render_commit, - sg_commit(); -#ifdef TRACY_ENABLE - render_dump_trace(); -#endif -) -JSC_CCALL(render_end_pass, sg_end_pass()) HMM_Mat4 transform2view(transform *t) { @@ -657,13 +633,6 @@ HMM_Mat4 transform2view(transform *t) return ret; } -JSC_CCALL(render_camera_screen2world, - HMM_Mat4 view = transform2view(js2transform(js, js_getpropertystr(js,argv[0], "transform"))); - view = HMM_InvGeneralM4(view); - HMM_Vec4 p = js2vec4(js, argv[1]); - return vec42js(js, HMM_MulM4V4(view, p)); -) - JSC_CCALL(render_set_projection_ortho, lrtb extents = js2lrtb(js, argv[0]); float nearme = js2number(js,argv[1]); @@ -693,415 +662,6 @@ JSC_CCALL(render_set_view, globalview.vp = HMM_MulM4(globalview.p, globalview.v); ) -sg_shader_uniform_block_desc js2uniform_block(JSContext *js,JSValue v) -{ - sg_shader_uniform_block_desc desc = {0}; -// int slot = js2number(js,js_getpropertystr(js,v, "slot")); - JS_GETPROPSTR(js,v,desc,size,number) - desc.layout = SG_UNIFORMLAYOUT_STD140; - - JSValue uniforms = js_getpropertystr(js,v, "uniforms"); - for (int j = 0; j < js_arrlen(js,uniforms); j++) { - JSValue uniform = JS_GetPropertyUint32(js, uniforms, j); - desc.uniforms[j].name = js2strdup(js, js_getpropertystr(js,v, "struct_name")); - JS_GETPROPSTR(js,uniform,desc.uniforms[j],array_count,number) - desc.uniforms[j].type = SG_UNIFORMTYPE_FLOAT4; - JS_FreeValue(js,uniform); - } - - return desc; -} - -sg_shader js2shader(JSContext *js,JSValue v) -{ - sg_shader_desc desc = {0}; - JSValue prog = v; - desc.label = js2strdup(js, js_getpropertystr(js,v, "name")); - JSValue vs = js_getpropertystr(js,prog, "vs"); - JSValue fs = js_getpropertystr(js,prog, "fs"); - const char *vsf = JS_ToCString(js, js_getpropertystr(js,vs, "code")); - const char *fsf = JS_ToCString(js, js_getpropertystr(js,fs, "code")); - desc.vs.source = vsf; - desc.fs.source = fsf; - const char *vsmain = JS_ToCString(js, js_getpropertystr(js,vs, "entry_point")); - const char *fsmain = JS_ToCString(js, js_getpropertystr(js,fs, "entry_point")); - desc.vs.entry = vsmain; - desc.fs.entry = fsmain; - desc.vs.d3d11_target = "vs_4_0"; - desc.fs.d3d11_target = "ps_4_0"; - JSValue attrs = js_getpropertystr(js,vs, "inputs"); - int atin = js_arrlen(js,attrs); - for (int i = 0; i < atin; i++) { - JSValue u = JS_GetPropertyUint32(js,attrs,i); - int slot = js2number(js,js_getpropertystr(js,u, "slot")); - desc.attrs[slot].sem_name = js2strdup(js,js_getpropertystr(js,u,"sem_name")); - desc.attrs[slot].sem_index = js2number(js,js_getpropertystr(js,u, "sem_index")); - JS_FreeValue(js,u); - } - - JSValue vsu = JS_GetPropertyStr(js,vs, "uniform_blocks"); - for (int i = 0; i < js_arrlen(js,vsu); i++) { - JSValue v = JS_GetPropertyUint32(js,vsu,i); - desc.vs.uniform_blocks[i] = js2uniform_block(js,v); - JS_FreeValue(js,v); - } - JS_FreeValue(js,vsu); - - JSValue fsu = JS_GetPropertyStr(js,fs, "uniform_blocks"); - for (int i = 0; i < js_arrlen(js,fsu); i++) { - JSValue v = JS_GetPropertyUint32(js,fsu,i); - desc.fs.uniform_blocks[i] = js2uniform_block(js,v); - JS_FreeValue(js,v); - } - JS_FreeValue(js,fsu); - - JSValue imgs = JS_GetPropertyStr(js,fs, "images"); - for (int i = 0; i < js_arrlen(js,imgs); i++) { - JSValue u = JS_GetPropertyUint32(js,imgs,i); -// int slot = js2number(js,js_getpropertystr(js,u, "slot")); - desc.fs.images[i].used = true; - desc.fs.images[i].multisampled = JS_ToBool(js,js_getpropertystr(js,u, "multisampled")); - desc.fs.images[i].image_type = SG_IMAGETYPE_2D; - desc.fs.images[i].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - JS_FreeValue(js,u); - } - JS_FreeValue(js,imgs); - - JSValue samps = JS_GetPropertyStr(js,fs, "samplers"); - for (int i = 0; i < js_arrlen(js,samps); i++) { - JSValue sampler = JS_GetPropertyUint32(js, samps, i); - desc.fs.samplers[0].used = true; - desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - JS_FreeValue(js,sampler); - } - JS_FreeValue(js,samps); - - JSValue pairs = JS_GetPropertyStr(js,fs, "image_sampler_pairs"); - for (int i = 0; i < js_arrlen(js,pairs); i++) { - JSValue pair = JS_GetPropertyUint32(js, pairs, i); - desc.fs.image_sampler_pairs[0].used = true; - desc.fs.image_sampler_pairs[0].image_slot = js2number(js,js_getpropertystr(js,pair, "slot")); - desc.fs.image_sampler_pairs[0].sampler_slot = 0; - desc.fs.image_sampler_pairs[0].glsl_name = js2strdup(js,js_getpropertystr(js,pair, "name")); - JS_FreeValue(js,pair); - } - JS_FreeValue(js,pairs); - - JSValue ssbos = JS_GetPropertyStr(js,vs, "storage_buffers"); - for (int i = 0; i < js_arrlen(js,ssbos); i++) { - desc.vs.storage_buffers[i].used = true; - desc.vs.storage_buffers[i].readonly = true; - } - JS_FreeValue(js,ssbos); - - sg_shader sh = sg_make_shader(&desc); - - JS_FreeCString(js,vsf); - JS_FreeCString(js,fsf); - JS_FreeCString(js,vsmain); - JS_FreeCString(js,fsmain); - - return sh; -} - -static int mat2type(int mat) -{ - switch(mat) { - case MAT_POS: - case MAT_NORM: - return SG_VERTEXFORMAT_FLOAT3; - case MAT_PPOS: - case MAT_WH: - case MAT_ST: - return SG_VERTEXFORMAT_FLOAT2; - case MAT_UV: - return SG_VERTEXFORMAT_USHORT2N; - case MAT_TAN: - return SG_VERTEXFORMAT_UINT10_N2; - case MAT_BONE: - return SG_VERTEXFORMAT_UBYTE4; - case MAT_WEIGHT: - case MAT_COLOR: - return SG_VERTEXFORMAT_UBYTE4N; - case MAT_ANGLE: - case MAT_SCALE: - return SG_VERTEXFORMAT_FLOAT; - }; - - return -1; -} - -sg_vertex_layout_state js2vertex_layout(JSContext *js,JSValue v) -{ - sg_vertex_layout_state st = {0}; - JSValue inputs = js_getpropertystr(js,js_getpropertystr(js,v, "vs"), "inputs"); - for (int i = 0; i < js_arrlen(js,inputs); i++) { - JSValue attr = JS_GetPropertyUint32(js, inputs, i); - int slot = js2number(js,js_getpropertystr(js,attr, "slot")); - int mat = js2number(js,js_getpropertystr(js,attr, "mat")); - st.attrs[slot].format = mat2type(mat); - st.attrs[slot].buffer_index = slot; - JS_FreeValue(js,attr); - } - - return st; -} - -sg_depth_state js2depth(JSContext *js,JSValue v) -{ - sg_depth_state depth = {0}; - JS_GETPROPSTR(js,v,depth,compare,number) - JS_GETPROPSTR(js,v,depth,write_enabled,bool) - JS_GETPROPSTR(js,v,depth,bias,number) - JS_GETPROPSTR(js,v,depth,bias_slope_scale,number) - JS_GETPROPSTR(js,v,depth,bias_clamp,number) - return depth; -} - -sg_stencil_face_state js2face_state(JSContext *js,JSValue v) -{ - sg_stencil_face_state face = {0}; - JS_GETPROPSTR(js,v,face,compare,number) - JS_GETPROPSTR(js,v,face,fail_op,number) - JS_GETPROPSTR(js,v,face,depth_fail_op,number) - JS_GETPROPSTR(js,v,face,pass_op,number) - return face; -} - -sg_stencil_state js2stencil(JSContext *js,JSValue v) -{ - sg_stencil_state stencil = {0}; - JS_GETPROPSTR(js,v,stencil,enabled,bool) - JS_GETPROPSTR(js,v,stencil,read_mask,bool) - JS_GETPROPSTR(js,v,stencil,write_mask,bool) - JS_GETPROPSTR(js,v,stencil,enabled,bool) - JS_GETPROPSTR(js,v,stencil,front,face_state) - JS_GETPROPSTR(js,v,stencil,back,face_state) - JS_GETPROPSTR(js,v,stencil,ref,number) - return stencil; -} - -sg_blend_state js2blend(JSContext *js,JSValue v) -{ - sg_blend_state blend = {0}; - JS_GETPROPSTR(js,v,blend,enabled,bool) - JS_GETPROPSTR(js,v,blend,src_factor_rgb,number) - JS_GETPROPSTR(js,v,blend,dst_factor_rgb,number) - JS_GETPROPSTR(js,v,blend,op_rgb,number) - JS_GETPROPSTR(js,v,blend,src_factor_alpha,number) - JS_GETPROPSTR(js,v,blend,dst_factor_alpha,number) - JS_GETPROPSTR(js,v,blend,op_alpha,number) - return blend; -} - -JSC_CCALL(render_make_pipeline, - sg_pipeline_desc p = {0}; - p.shader = js2shader(js,argv[0]); - p.layout = js2vertex_layout(js,argv[0]); - p.primitive_type = js2number(js,js_getpropertystr(js,argv[0], "primitive")); - if (JS_ToBool(js,js_getpropertystr(js,argv[0], "indexed"))) - p.index_type = SG_INDEXTYPE_UINT16; - - JSValue pipe = argv[1]; - JS_GETPROPSTR(js,pipe,p,primitive_type,number) - JS_GETPROPSTR(js,pipe,p,cull_mode,number) - JS_GETPROPSTR(js,pipe,p,face_winding,number) - JS_GETPROPSTR(js,pipe,p,colors[0].blend,blend) - JS_GETPROPSTR(js,pipe,p,colors[0].write_mask,number) - JS_GETPROPSTR(js,pipe,p,alpha_to_coverage_enabled,bool) - JS_GETPROPSTR(js,pipe,p,depth,depth) - JS_GETPROPSTR(js,pipe,p,stencil,stencil) - - sg_pipeline *g = malloc(sizeof(*g)); - *g = sg_make_pipeline(&p); - return sg_pipeline2js(js,g); -) - -JSC_CCALL(render_setuniv, - HMM_Vec4 f = {0}; - f.x = js2number(js,argv[2]); - sg_apply_uniforms(js2number(js,argv[0]), js2number(js,argv[1]), SG_RANGE_REF(f)); -) - -JSC_CCALL(render_setuniv2, - HMM_Vec4 v = {0}; - v.xy = js2vec2(js,argv[2]); - sg_apply_uniforms(js2number(js,argv[0]), js2number(js,argv[1]), SG_RANGE_REF(v.e)); -) - -JSC_CCALL(render_setuniv3, - HMM_Vec4 f = {0}; - f.xyz = js2vec3(js,argv[2]); - sg_apply_uniforms(js2number(js,argv[0]), js2number(js,argv[1]), SG_RANGE_REF(f.e)); -) - -JSC_CCALL(render_setuniv4, - HMM_Vec4 v = {0}; - if (JS_IsArray(js, argv[2])) { - for (int i = 0; i < js_arrlen(js,argv[2]); i++) - v.e[i] = js_getnum_uint32(js, argv[2], i); - } else - v.x = js2number(js,argv[2]); - - sg_apply_uniforms(js2number(js,argv[0]), js2number(js,argv[1]), SG_RANGE_REF(v.e)); -) - -JSC_CCALL(render_setuniproj, - sg_apply_uniforms(js2number(js,argv[0]), js2number(js,argv[1]), SG_RANGE_REF(globalview.p.e)); -) - -JSC_CCALL(render_setuniview, - sg_apply_uniforms(js2number(js,argv[0]), js2number(js,argv[1]), SG_RANGE_REF(globalview.v.e)); -) - -JSC_CCALL(render_setunivp, - sg_apply_uniforms(js2number(js,argv[0]), js2number(js,argv[1]), SG_RANGE_REF(globalview.vp.e)); -) - -JSC_CCALL(render_setunibones, - skin *sk = js2skin(js, argv[2]); - sg_apply_uniforms(js2number(js,argv[0]), js2number(js,argv[1]), SG_RANGE_REF(sk->binds)); -) - -JSC_CCALL(render_setunim4, - HMM_Mat4 m = MAT1; - if (JS_IsArray(js, argv[2])) { - JSValue arr = argv[2]; - int n = js_arrlen(js,arr); - if (n == 1) - m = transform2mat(js2transform(js,js_getpropertyuint32(js, arr,0))); - else { - for (int i = 0; i < n; i++) { - HMM_Mat4 p = transform2mat(js2transform(js,js_getpropertyuint32(js, arr, i))); - m = HMM_MulM4(p,m); - } - } - } else if (!JS_IsUndefined(argv[2])) - m = transform2mat(js2transform(js,argv[2])); - - sg_apply_uniforms(js2number(js,argv[0]), js2number(js,argv[1]), SG_RANGE_REF(m.e)); -); - -JSC_CCALL(render_setbind, - sg_bindings bind = js2bind(js,argv[0]); - sg_apply_bindings(&bind); -) - -typedef struct particle_ss { - HMM_Mat4 model; - HMM_Vec4 color; -} particle_ss; - -JSC_CCALL(render_make_particle_ssbo, - JSValue array = argv[0]; - size_t size = js_arrlen(js,array)*(sizeof(particle_ss)); - sg_buffer *b = js2sg_buffer(js, argv[1]); - if (!b) return JS_UNDEFINED; - particle_ss ms[js_arrlen(js,array)]; - - if (sg_query_buffer_will_overflow(*b, size)) { - sg_buffer_desc desc = sg_query_buffer_desc(*b); - sg_destroy_buffer(*b); - - *b = sg_make_buffer(&(sg_buffer_desc){ - .type = SG_BUFFERTYPE_STORAGEBUFFER, - .size = size+desc.size, - .usage = SG_USAGE_STREAM, - .label = "particle ssbo buffer" - }); - } - - for (int i = 0; i < js_arrlen(js,array); i++) { - JSValue sub = js_getpropertyuint32(js, array,i); - ms[i].model = transform2mat(js2transform(js,js_getpropertystr(js,sub, "transform"))); - ms[i].color = js2vec4(js,js_getpropertystr(js,sub,"color")); - } - - int offset = sg_append_buffer(*b, (&(sg_range){ - .ptr = ms, - .size = size - })); - - ret = number2js(js,offset/sizeof(particle_ss)); -) - -typedef struct sprite_ss { - HMM_Mat4 model; - rect rect; - HMM_Vec4 shade; -} sprite_ss; - -JSC_CCALL(render_make_sprite_ssbo, - JSValue array = argv[0]; - size_t size = js_arrlen(js,array)*(sizeof(sprite_ss)); - sg_buffer *b = js2sg_buffer(js, argv[1]); - if (!b) return JS_UNDEFINED; - - sprite_ss ms[js_arrlen(js,array)]; - - if (sg_query_buffer_will_overflow(*b, size)) { - sg_buffer_desc desc = sg_query_buffer_desc(*b); - sg_destroy_buffer(*b); - *b = sg_make_buffer(&(sg_buffer_desc){ - .type = SG_BUFFERTYPE_STORAGEBUFFER, - .size = size+desc.size, - .usage = SG_USAGE_STREAM, - .label = "sprite ssbo buffer" - }); - } - - for (int i = 0; i < js_arrlen(js,array); i++) { - JSValue sub = js_getpropertyuint32(js, array,i); - -// transform *tr = js2transform(js,js_getpropertystr(js,sub, "transform")); - JSValue image = js_getpropertystr(js,sub, "image"); - - ms[i].model = js2transform_mat(js, js_getpropertystr(js,sub,"transform"));// transform2mat(tr); - ms[i].rect = js2rect(js,js_getpropertystr(js,image,"rect")); - ms[i].shade = js2vec4(js,js_getpropertystr(js,sub,"shade")); - } - - int offset = sg_append_buffer(*b, (&(sg_range){ - .ptr = ms, - .size = size - })); - - ret = number2js(js,offset/sizeof(sprite_ss)); // 96 size of a sprite struct -) - -JSC_CCALL(render_make_t_ssbo, - JSValue array = argv[0]; - size_t size = js_arrlen(js,array)*sizeof(HMM_Mat4); - sg_buffer *b = js2sg_buffer(js, argv[1]); - if (!b) return JS_UNDEFINED; - - HMM_Mat4 ms[js_arrlen(js,array)]; - - if (sg_query_buffer_will_overflow(*b, size)) { - sg_destroy_buffer(*b); - *b = sg_make_buffer(&(sg_buffer_desc){ - .type = SG_BUFFERTYPE_STORAGEBUFFER, - .size = size, - .usage = SG_USAGE_STREAM, - .label = "transform buffer" - }); - } - - for (int i = 0; i < js_arrlen(js,array); i++) - ms[i] = transform2mat(js2transform(js,js_getpropertyuint32(js, array, i))); - - sg_append_buffer(*b, (&(sg_range){ - .ptr = ms, - .size = size - })); -) - -JSC_CCALL(render_spdraw, - sg_draw(js2number(js,argv[0]),js2number(js,argv[1]),js2number(js,argv[2])); -) - -JSC_CCALL(render_setpipeline, sg_apply_pipeline(*js2sg_pipeline(js,argv[0]));) - JSC_SCALL(render_text_size, font *f = js2font(js,argv[1]); float size = js2number(js,argv[2]); @@ -1111,58 +671,108 @@ JSC_SCALL(render_text_size, ret = vec22js(js,measure_text(str, f, size, letterSpacing, wrap)); ) +JSC_CCALL(render_draw_color, + SDL_Renderer *renderer = js2SDL_Renderer(js,self); + struct rgba rgba = js2color(js,argv[0]); + SDL_SetRenderDrawColor(renderer, rgba.r, rgba.g, rgba.b, rgba.a); +) + static const JSCFunctionListEntry js_render_funcs[] = { - MIST_FUNC_DEF(render, flushtext, 1), - MIST_FUNC_DEF(render, camera_screen2world, 2), - MIST_FUNC_DEF(render, make_textssbo, 0), - MIST_FUNC_DEF(render, viewport, 4), - MIST_FUNC_DEF(render, end_pass, 0), - MIST_FUNC_DEF(render, commit, 0), - MIST_FUNC_DEF(render, glue_pass, 0), MIST_FUNC_DEF(render, text_size, 5), MIST_FUNC_DEF(render, set_projection_ortho, 3), MIST_FUNC_DEF(render, set_projection_perspective, 4), MIST_FUNC_DEF(render, set_view, 1), - MIST_FUNC_DEF(render, make_pipeline, 1), - MIST_FUNC_DEF(render, setuniv3, 2), - MIST_FUNC_DEF(render, setuniv, 2), - MIST_FUNC_DEF(render, spdraw, 3), - MIST_FUNC_DEF(render, setunibones, 3), - MIST_FUNC_DEF(render, setbind, 1), - MIST_FUNC_DEF(render, setuniproj, 2), - MIST_FUNC_DEF(render, setuniview, 2), - MIST_FUNC_DEF(render, setunivp, 2), - MIST_FUNC_DEF(render, setunim4, 3), - MIST_FUNC_DEF(render, setuniv2, 2), - MIST_FUNC_DEF(render, setuniv4, 2), - MIST_FUNC_DEF(render, setpipeline, 1), - MIST_FUNC_DEF(render, make_t_ssbo, 2), - MIST_FUNC_DEF(render, make_particle_ssbo, 2), - MIST_FUNC_DEF(render, make_sprite_ssbo, 2) }; -JSC_CCALL(gui_scissor, - sg_apply_scissor_rect(js2number(js,argv[0]), js2number(js,argv[1]), js2number(js,argv[2]), js2number(js,argv[3]), 0); -) +static JSValue idx_buffer = JS_UNDEFINED; +static int idx_count = 0; -JSC_CCALL(gui_text, +JSValue make_quad_indices_buffer(JSContext *js, int quads) +{ + int count = quads*6; + if (!JS_IsUndefined(idx_buffer) && idx_count >= count) + return JS_DupValue(js,idx_buffer); + + int verts = quads*4; + uint16_t *indices = malloc(sizeof(*indices)*count); + for (int i = 0, v = 0; v < verts; i +=6, v += 4) { + indices[i] = v; + indices[i+1] = v+1; + indices[i+2] = v+2; + indices[i+3] = v+2; + indices[i+4] = v+1; + indices[i+5] = v+3; + } + + if (!JS_IsUndefined(idx_buffer)) + JS_FreeValue(js,idx_buffer); + + idx_buffer = make_gpu_buffer(js,indices, sizeof(*indices)*count, JS_TYPED_ARRAY_UINT16, 1,0); + return JS_DupValue(js,idx_buffer); +} + +JSC_CCALL(os_make_text_buffer, const char *s = JS_ToCString(js, argv[0]); - HMM_Vec2 pos = js2vec2(js,argv[1]); + HMM_Vec2 startpos = js2vec2(js,argv[1]); float size = js2number(js,argv[2]); font *f = js2font(js,argv[5]); if (!size) size = f->height; struct rgba c = js2color(js,argv[3]); int wrap = js2number(js,argv[4]); - renderText(s, pos, f, size, c, wrap); + text_vert *buffer = renderText(s, startpos, f, size, c, wrap); + size_t verts = arrlen(buffer); + + HMM_Vec2 *pos = malloc(arrlen(buffer)*sizeof(HMM_Vec2)); + HMM_Vec2 *uv = malloc(arrlen(buffer)*sizeof(HMM_Vec2)); + HMM_Vec4 *color = malloc(arrlen(buffer)*sizeof(HMM_Vec4)); + + for (int i = 0; i < arrlen(buffer); i++) { + pos[i] = buffer[i].pos; + pos[i].y *= -1; + pos[i].y += logical.y; + uv[i] = buffer[i].uv; + color[i] = buffer[i].color; + } + + arrfree(buffer); + + JSValue jspos = make_gpu_buffer(js, pos, sizeof(HMM_Vec2)*arrlen(buffer), JS_TYPED_ARRAY_FLOAT32, 2,0); + JSValue jsuv = make_gpu_buffer(js, uv, sizeof(HMM_Vec2)*arrlen(buffer), JS_TYPED_ARRAY_FLOAT32, 2,0); + JSValue jscolor = make_gpu_buffer(js, color, sizeof(HMM_Vec4)*arrlen(buffer), JS_TYPED_ARRAY_FLOAT32, 4,0); + +/* + JSValue jsbuffer = JS_NewArrayBuffer(js,buffer,sizeof(*buffer)*arrlen(buffer), free_gpu_buffer, NULL, 0); + JSValue tstack[3]; + tstack[0] = jsbuffer; + tstack[1] = JS_UNDEFINED;//number2js(js,0); + tstack[2] = JS_UNDEFINED; + JSValue jspos = JS_NewTypedArray(js, 3, tstack, JS_TYPED_ARRAY_FLOAT32); + JS_SetPropertyStr(js,jspos, "stride", number2js(js,sizeof(*buffer))); + tstack[1] = number2js(js,8); + JSValue jsuv = JS_NewTypedArray(js,3,tstack,JS_TYPED_ARRAY_FLOAT32); + JS_SetPropertyStr(js,jsuv, "stride", number2js(js,sizeof(*buffer))); + tstack[1] = number2js(js,16); + JSValue jscolor = JS_NewTypedArray(js,3,tstack,JS_TYPED_ARRAY_FLOAT32); + JS_SetPropertyStr(js,jscolor, "stride", number2js(js,sizeof(*buffer))); +*/ + + size_t quads = verts/4; + size_t count = verts/2*3; + JSValue jsidx = make_quad_indices_buffer(js, quads); + JS_FreeCString(js, s); + + ret = JS_NewObject(js); + JS_SetProperty(js, ret, pos_atom, jspos); + JS_SetProperty(js, ret, uv_atom, jsuv); + JS_SetProperty(js, ret, color_atom, jscolor); + JS_SetProperty(js, ret, indices_atom, jsidx); + JS_SetProperty(js, ret, vertices_atom, number2js(js, verts)); + JS_SetProperty(js, ret, count_atom, number2js(js, count)); + return ret; ) -static const JSCFunctionListEntry js_gui_funcs[] = { - MIST_FUNC_DEF(gui, scissor, 4), - MIST_FUNC_DEF(gui, text, 6), -}; - JSC_CCALL(spline_catmull, HMM_Vec2 *points = js2cpvec2arr(js,argv[0]); float param = js2number(js,argv[1]); @@ -1190,7 +800,15 @@ static const JSCFunctionListEntry js_spline_funcs[] = { MIST_FUNC_DEF(spline, bezier, 2) }; -JSValue js_vector_dot(JSContext *js, JSValue self, int argc, JSValue *argv) { return number2js(js,HMM_DotV2(js2vec2(js,argv[0]), js2vec2(js,argv[1]))) ; }; +JSValue js_vector_dot(JSContext *js, JSValue self, int argc, JSValue *argv) { + size_t alen, blen; + float *a = js2floats(js,argv[0], &alen); + float *b = js2floats(js,argv[1], &blen); + JSValue ret = number2js(js, cblas_sdot(alen, a, 1, b,1)); + free(a); + free(b); + return ret; +}; JSC_CCALL(vector_project, return vec22js(js,HMM_ProjV2(js2vec2(js,argv[0]), js2vec2(js,argv[1])))) @@ -1265,6 +883,31 @@ JSC_CCALL(vector_inflate, arrfree(p); ) +JSC_CCALL(vector_rotate, + HMM_Vec2 vec = js2vec2(js,argv[0]); + double angle = js2angle(js, argv[1]); + HMM_Vec2 pivot = JS_IsUndefined(argv[2]) ? v2zero : js2vec2(js,argv[2]); + // vec = vec - pivot + cblas_saxpy(2, -1.0f, pivot.e, 1, vec.e, 1); + + // Length of the vector (r) + float r = sqrtf(cblas_sdot(2, vec.e, 1, vec.e, 1)); + + // Update angle + angle += atan2f(vec.y, vec.x); + + // Update vec to rotated position + vec.x = r * cosf(angle); + vec.y = r * sinf(angle); + + // vec = vec + pivot + cblas_saxpy(2, 1.0f, pivot.e, 1, vec.e, 1); + + // Convert back to JS and return + return vec22js(js, vec); +) +/* + JSC_CCALL(vector_rotate, HMM_Vec2 vec = js2vec2(js,argv[0]); double angle = js2angle(js,argv[1]); @@ -1276,7 +919,7 @@ JSC_CCALL(vector_rotate, vec.y = r*sin(angle); return vec22js(js,HMM_AddV2(vec,pivot)); ) - +*/ JSC_CCALL(vector_add, HMM_Vec4 a = js2vec4(js,argv[0]); HMM_Vec4 b = js2vec4(js,argv[1]); @@ -1414,6 +1057,14 @@ JSC_CCALL(vector_sum, return number2js(js,sum); ) +JSC_CCALL(vector_fastsum, + float sum = 0.0; + size_t len; + float *a = get_typed_buffer(js, argv[0], &len); + sum = cblas_sasum(len, a,1); + ret = number2js(js,sum); +) + JSC_CCALL(vector_sigma, int len = js_arrlen(js,argv[0]); double sum; @@ -1490,6 +1141,19 @@ JSC_CCALL(vector_from_to, JS_SetPropertyUint32(js, ret, steps+1, vec22js(js,to)); ) +JSC_CCALL(vector_float32add, + size_t len; + float *vec_a = get_typed_buffer(js,self, &len); + float *vec_b = get_typed_buffer(js,argv[0], &len); + cblas_saxpy(len,1.0f,vec_b,1,vec_a,1); + JSValue tstack[3]; + tstack[0] = JS_NewArrayBufferCopy(js,vec_a,sizeof(float)*4); + tstack[1] = JS_UNDEFINED; + tstack[2] = JS_UNDEFINED; + ret = JS_NewTypedArray(js, 3, tstack, JS_TYPED_ARRAY_FLOAT32); + JS_FreeValue(js,tstack[0]); +) + static const JSCFunctionListEntry js_vector_funcs[] = { MIST_FUNC_DEF(vector, dot,2), MIST_FUNC_DEF(vector, project,2), @@ -1511,11 +1175,13 @@ static const JSCFunctionListEntry js_vector_funcs[] = { MIST_FUNC_DEF(vector, random_range, 2), MIST_FUNC_DEF(vector, mean, 1), MIST_FUNC_DEF(vector, sum, 1), + MIST_FUNC_DEF(vector, fastsum, 1), MIST_FUNC_DEF(vector, sigma, 1), MIST_FUNC_DEF(vector, median, 1), MIST_FUNC_DEF(vector, length, 1), MIST_FUNC_DEF(vector, fib, 1), MIST_FUNC_DEF(vector, from_to, 5), + MIST_FUNC_DEF(vector, float32add, 2), }; #define JS_HMM_FN(OP, HMM, SIGN) \ @@ -1546,6 +1212,53 @@ JSC_CCALL(array_##OP, \ return arr; \ ) \ +/*JSC_CCALL(array_add, + int len = js_arrlen(js,self); + if (!JS_IsArray(js, argv[0])) { + double n = js2number(js,argv[0]); + JSValue arr = JS_NewArray(js); + for (int i = 0; i < len; i++) + JS_SetPropertyUint32(js, arr, i, number2js(js,js_getnum_uint32(js, self,i) + n)); + return arr; + } + + JSValue arr = JS_NewArray(js); + size_t len_a, len_b; + float *a = js2floats(js,self, &len_a); + float *b = js2floats(js,argv[0], &len_b); + cblas_saxpy(len_a, 1.0, a, 1, b, 1); + for (int i = 0; i < len; i++) + JS_SetPropertyUint32(js, arr, i, number2js(js,b[i])); + + ret = arr; + free(a); + free(b); + return arr; +) */ + +/*JSC_CCALL(array_add, + int len = js_arrlen(js,self); + if (!JS_IsArray(js,argv[0])) { + double n = js2number(js,argv[0]); + JSValue arr = JS_NewArray(js); + for (int i = 0; i < len; i++) + JS_SetPropertyUint32(js,arr,i,number2js(js,js_getnum_uint32(js,self,i) + n)); + + return arr; + } + float *vec_a = js2floatarray(js,self); + float *vec_b = js2floatarray(js,argv[0]); + cblas_saxpy(len,1.0f,vec_b,1,vec_a,1); + JSValue tstack[3]; + tstack[0] = JS_NewArrayBuffer(js,vec_a,sizeof(float)*2,free_gpu_buffer, NULL, 0); + tstack[1] = JS_UNDEFINED; + tstack[2] = JS_UNDEFINED; + ret = JS_NewTypedArray(js, 3, tstack, JS_TYPED_ARRAY_FLOAT32); + JS_FreeValue(js,tstack[0]); + free(vec_b); +) +*/ + JS_HMM_FN(add, Add, +) JS_HMM_FN(sub, Sub, -) JS_HMM_FN(div, Div, /) @@ -1572,90 +1285,539 @@ static const JSCFunctionListEntry js_array_funcs[] = { PROTO_FUNC_DEF(array, lerp, 2) }; -static JSValue js_sg_init; -static JSValue js_sg_frame; -static JSValue js_sg_event; -static JSValue js_sg_cleanup; +JSC_SCALL(game_engine_start, + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_CAMERA) < 0) + return JS_ThrowReferenceError("Couldn't initialize SDL: %s\n", SDL_GetError()); -static void c_init(JSContext *js) -{ - render_init(); - script_call_sym(js_sg_init, 0,NULL); -} + const char *title = JS_ToCString(js,js_getpropertystr(js,argv[0], "title")); + SDL_Window *new = SDL_CreateWindow(title, js2number(js, js_getproperty(js,argv[0], width_atom)), js2number(js,js_getproperty(js,argv[0], height_atom)), SDL_WINDOW_RESIZABLE); -static void c_frame(JSContext *js) -{ - script_call_sym(js_sg_frame,0,NULL); -} + if (!new) return JS_ThrowReferenceError("Couldn't open window: %s\n", SDL_GetError()); -static void c_cleanup(JSContext *js) -{ - script_call_sym(js_sg_cleanup,0,NULL); - sg_shutdown(); - sapp_quit(); -} + SDL_StartTextInput(new); -void gui_input(sapp_event *e); - -static void c_event(const sapp_event *e, JSContext *js) -{ -#ifndef NEDITOR - gui_input(e); -#endif - - JSValue event = sapp_event2js(js, e); - script_call_sym(js_sg_event, 1, &event); - JS_FreeValue(js,event); -} - -JSC_CCALL(game_engine_start, - sapp_desc start_desc = {0}; - - start_desc.user_data = js; - start_desc.init_userdata_cb = c_init; - start_desc.frame_userdata_cb = c_frame; - start_desc.event_userdata_cb = c_event; - start_desc.cleanup_userdata_cb = c_cleanup; - js_sg_init = JS_DupValue(js, js_getpropertystr(js,argv[0], "init")); - js_sg_frame = JS_DupValue(js, js_getpropertystr(js,argv[0], "frame")); - js_sg_cleanup = JS_DupValue(js, js_getpropertystr(js,argv[0], "cleanup")); - js_sg_event = JS_DupValue(js, js_getpropertystr(js,argv[0], "event")); - start_desc.width = js2number(js, js_getpropertystr(js, argv[0], "width")); - start_desc.height = js2number(js, js_getpropertystr(js, argv[0], "height")); - start_desc.sample_count = js2number(js, js_getpropertystr(js, argv[0], "sample_count")); - start_desc.high_dpi = js2number(js, js_getpropertystr(js, argv[0], "high_dpi")); - start_desc.alpha = js2number(js, js_getpropertystr(js, argv[0], "alpha")); - start_desc.fullscreen = js2number(js, js_getpropertystr(js, argv[0], "fullscreen")); - start_desc.swap_interval = js2number(js, js_getpropertystr(js, argv[0], "swap_interval")); - start_desc.window_title = JS_ToCString(js, js_getpropertystr(js, argv[0], "title")); - start_desc.enable_clipboard = JS_ToBool(js, js_getpropertystr(js, argv[0], "enable_clipboard")); - start_desc.enable_dragndrop = JS_ToBool(js, js_getpropertystr(js, argv[0], "enable_dragndrop")); - start_desc.max_dropped_files = js2number(js, js_getpropertystr(js, argv[0], "max_dropped_files")); - start_desc.max_dropped_file_path_length = 2048; - start_desc.max_dropped_files = 4; - start_desc.logger.func = slog_func; - texture *tex = js2texture(js, js_getpropertystr(js, argv[0], "icon")); - if (tex) start_desc.icon = texture2icon(tex); - sapp_run(&start_desc); + return SDL_Window2js(js,new); ) -JSC_CCALL(game_fullscreen, sapp_toggle_fullscreen()); +static JSValue event2js(JSContext *js, SDL_Event event) +{ + JSValue e = JS_NewObject(js); + JS_SetPropertyStr(js,e,"timestamp", number2js(js,event.common.timestamp)); + + switch(event.type) { + case SDL_EVENT_QUIT: + JS_SetPropertyStr(js,e,"type", JS_NewString(js,"quit")); + break; + case SDL_EVENT_MOUSE_MOTION: + JS_SetPropertyStr(js, e, "type", JS_NewString(js, "mouse")); + JS_SetPropertyStr(js,e,"window", number2js(js,event.motion.windowID)); + JS_SetPropertyStr(js,e,"which", number2js(js,event.motion.which)); + JS_SetPropertyStr(js, e, "state", number2js(js,event.motion.state)); + JS_SetPropertyStr(js,e, "mouse", vec22js(js,(HMM_Vec2){event.motion.x,event.motion.y})); + JS_SetPropertyStr(js,e,"mouse_d", vec22js(js,(HMM_Vec2){event.motion.xrel, event.motion.yrel})); + break; + case SDL_EVENT_MOUSE_WHEEL: + JS_SetPropertyStr(js,e,"type",JS_NewString(js,"wheel")); + JS_SetPropertyStr(js,e,"window", number2js(js,event.wheel.windowID)); + JS_SetPropertyStr(js,e,"which", number2js(js,event.wheel.which)); + JS_SetPropertyStr(js,e,"scroll", vec22js(js,(HMM_Vec2){event.wheel.x,event.wheel.y})); + JS_SetPropertyStr(js,e, "mouse", vec22js(js,(HMM_Vec2){event.wheel.mouse_x,event.wheel.mouse_y})); + break; + case SDL_EVENT_MOUSE_BUTTON_UP: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + JS_SetPropertyStr(js,e,"type",JS_NewString(js,"mouse_button")); + JS_SetPropertyStr(js,e,"window", number2js(js,event.button.windowID)); + JS_SetPropertyStr(js,e,"which", number2js(js,event.button.which)); + JS_SetPropertyStr(js,e,"down", JS_NewBool(js,event.button.down)); + JS_SetPropertyStr(js,e,"clicks", number2js(js,event.button.clicks)); + JS_SetPropertyStr(js,e,"mouse", vec22js(js,(HMM_Vec2){event.button.x,event.button.y})); + break; + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + JS_SetPropertyStr(js,e,"type", JS_NewString(js,"key")); + JS_SetPropertyStr(js,e,"window", number2js(js,event.key.windowID)); + JS_SetPropertyStr(js,e,"which", number2js(js,event.key.which)); + JS_SetPropertyStr(js,e,"down", JS_NewBool(js,event.key.down)); + JS_SetPropertyStr(js,e,"repeat", JS_NewBool(js,event.key.repeat)); + JS_SetPropertyStr(js,e,"key", number2js(js,event.key.key)); + JS_SetPropertyStr(js,e,"scancode", number2js(js,event.key.scancode)); + JS_SetPropertyStr(js,e,"mod", number2js(js,event.key.mod)); + break; + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + JS_SetPropertyStr(js,e,"type", JS_NewString(js,"touch")); + JS_SetPropertyStr(js,e,"touch", number2js(js,event.tfinger.touchID)); + JS_SetPropertyStr(js,e,"finger", number2js(js,event.tfinger.fingerID)); + JS_SetPropertyStr(js,e,"pos", vec22js(js, (HMM_Vec2){event.tfinger.x, event.tfinger.y})); + JS_SetPropertyStr(js,e,"pos_d", vec22js(js,(HMM_Vec2){event.tfinger.x, event.tfinger.dy})); + JS_SetPropertyStr(js,e,"pressure", number2js(js,event.tfinger.pressure)); + JS_SetPropertyStr(js,e,"window", number2js(js,event.key.windowID)); + break; + case SDL_EVENT_DROP_BEGIN: + case SDL_EVENT_DROP_FILE: + case SDL_EVENT_DROP_TEXT: + case SDL_EVENT_DROP_COMPLETE: + case SDL_EVENT_DROP_POSITION: + JS_SetPropertyStr(js,e,"type", JS_NewString(js,"drop")); + JS_SetPropertyStr(js,e,"window", number2js(js,event.drop.windowID)); + JS_SetPropertyStr(js,e,"pos", vec22js(js, (HMM_Vec2){event.drop.x,event.drop.y})); + JS_SetPropertyStr(js,e,"data", JS_NewString(js,event.drop.data)); + JS_SetPropertyStr(js,e,"source",JS_NewString(js,event.drop.source)); + break; + case SDL_EVENT_TEXT_INPUT: + JS_SetPropertyStr(js,e,"type", JS_NewString(js,"text")); + JS_SetPropertyStr(js,e,"window", number2js(js,event.text.windowID)); + JS_SetPropertyStr(js,e,"text", JS_NewString(js,event.text.text)); + break; + } + return e; +} + +// Polls and handles all input events +JSC_CCALL(game_engine_input, + SDL_Event event; + while (SDL_PollEvent(&event)) { + JSValue e = event2js(js,event); + JS_Call(js,argv[0], JS_UNDEFINED, 1, &e); + } +) + +JSC_CCALL(game_engine_delay, + SDL_Delay(js2number(js,argv[0])); +) + +JSC_CCALL(game_renderers, + int num = SDL_GetNumRenderDrivers(); + JSValue arr = JS_NewArray(js); + for (int i = 0; i < num; i++) + JS_SetPropertyUint32(js, arr, i, JS_NewString(js, SDL_GetRenderDriver(i))); + + return arr; +) + +JSC_CCALL(game_cameras, + SDL_CameraID *ids = SDL_GetCameras(NULL); + JSValue jsids = JS_NewArray(js); + + SDL_CameraID *id = ids; + while (*id) { + printf("camera %d\n", *id); + id++; + } +/* for (int i = 0; i < num; i++) { + JS_SetPropertyUint32(js,jsids, i, number2js(js,ids[i])); + } + + SDL_OpenCamera(ids[0], NULL);*/ + + return jsids; +) + +#include "wildmatch.h" +JSC_SSCALL(game_glob, + if (wildmatch(str, str2, WM_PATHNAME | WM_PERIOD | WM_WILDSTAR) == WM_MATCH) + return JS_NewBool(js,1); + else + return JS_NewBool(js, 0); +) static const JSCFunctionListEntry js_game_funcs[] = { MIST_FUNC_DEF(game, engine_start, 1), - MIST_FUNC_DEF(game, fullscreen, 0), + MIST_FUNC_DEF(game, engine_input,1), + MIST_FUNC_DEF(game, engine_delay, 1), + MIST_FUNC_DEF(game, renderers, 0), + MIST_FUNC_DEF(game, cameras, 0), + MIST_FUNC_DEF(game, glob, 2), }; -JSC_CCALL(input_show_keyboard, sapp_show_keyboard(JS_ToBool(js,argv[0]))) -JSValue js_input_keyboard_shown(JSContext *js, JSValue self) { return JS_NewBool(js,sapp_keyboard_shown()); } -JSC_CCALL(input_mouse_lock, sapp_lock_mouse(JS_ToBool(js,argv[0]))) -JSC_CCALL(input_mouse_cursor, sapp_set_mouse_cursor(js2number(js,argv[0]))) -JSC_CCALL(input_mouse_show, sapp_show_mouse(JS_ToBool(js,argv[0]))) +JSC_SCALL(SDL_Window_make_renderer, + SDL_Window *win = js2SDL_Window(js,self); + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0); + SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, win); + SDL_SetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, str); + SDL_Renderer *r = SDL_CreateRendererWithProperties(props); + SDL_DestroyProperties(props); + if (!r) return JS_ThrowReferenceError(js, SDL_GetError()); + SDL_SetRenderDrawBlendMode(r, SDL_BLENDMODE_BLEND); + return SDL_Renderer2js(js,r); +) + +JSC_CCALL(SDL_Window_fullscreen, + SDL_SetWindowFullscreen(js2SDL_Window(js,self), SDL_WINDOW_FULLSCREEN) +) + +JSValue js_SDL_Window_keyboard_shown(JSContext *js, JSValue self) { + SDL_Window *window = js2SDL_Window(js,self); + return JS_NewBool(js,SDL_ScreenKeyboardShown(window)); +} + + +static const JSCFunctionListEntry js_SDL_Window_funcs[] = { + MIST_FUNC_DEF(SDL_Window, fullscreen, 0), + MIST_FUNC_DEF(SDL_Window, make_renderer, 1), + MIST_FUNC_DEF(SDL_Window, keyboard_shown, 0), +}; + +JSC_CCALL(SDL_Renderer_clear, + SDL_Renderer *renderer = js2SDL_Renderer(js,self); + SDL_RenderClear(renderer); +) + +JSC_CCALL(SDL_Renderer_present, + SDL_RenderPresent(js2SDL_Renderer(js,self)); +) + +JSC_CCALL(SDL_Renderer_draw_color, + SDL_Renderer *renderer = js2SDL_Renderer(js,self); + struct rgba color = js2color(js,argv[0]); + SDL_SetRenderDrawColor(renderer, color.r,color.g,color.b,color.a); +) + +JSC_CCALL(SDL_Renderer_rect, + SDL_Renderer *r = js2SDL_Renderer(js,self); + if (!JS_IsUndefined(argv[1])) { + struct rgba color = js2color(js,argv[1]); + SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a); + } + + if (JS_IsArray(js,argv[0])) { + int len = js_arrlen(js,argv[0]); + rect rects[len]; + for (int i = 0; i < len; i++) { + JSValue val = JS_GetPropertyUint32(js,argv[0],i); + rects[i] = js2rect(js,val); + rects[i].y *= -1; + rects[i].y += logical.y; + rects[i].y -= rects[i].h; + JS_FreeValue(js,val); + } + SDL_RenderRects(r,rects,len); + return JS_UNDEFINED; + } + + rect rect = js2rect(js,argv[0]); + rect.y *= -1; + rect.y += logical.y; + rect.y -= rect.h; + + SDL_RenderRect(r, &rect); +) + +JSC_CCALL(renderer_load_texture, + SDL_Renderer *r = js2SDL_Renderer(js,self); + SDL_Surface *surf = js2SDL_Surface(js,argv[0]); + SDL_Texture *tex = SDL_CreateTextureFromSurface(r,surf); + ret = SDL_Texture2js(js,tex); + JS_SetProperty(js,ret,width_atom, number2js(js,tex->w)); + JS_SetProperty(js,ret,height_atom, number2js(js,tex->h)); +) + +JSC_CCALL(SDL_Renderer_fillrect, + SDL_Renderer *r = js2SDL_Renderer(js,self); + if (!JS_IsUndefined(argv[1])) { + struct rgba color = js2color(js,argv[1]); + SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a); + } + + if (JS_IsArray(js,argv[0])) { + int len = js_arrlen(js,argv[0]); + rect rects[len]; + for (int i = 0; i < len; i++) { + JSValue val = JS_GetPropertyUint32(js,argv[0],i); + rects[i] = js2rect(js,val); + JS_FreeValue(js,val); + } + SDL_RenderFillRects(r,rects,len); + return JS_UNDEFINED; + } + rect rect = js2rect(js,argv[0]); + rect.y *= -1; + rect.y += logical.y; + rect.y -= rect.h; + + SDL_RenderFillRect(r, &rect); +) + +JSC_CCALL(renderer_texture, + SDL_Renderer *renderer = js2SDL_Renderer(js,self); + SDL_Texture *tex = js2SDL_Texture(js,argv[0]); + rect dst = js2rect(js,argv[1]); + dst.y *= -1; + dst.y += logical.y; + dst.y -= dst.h; + + if (!JS_IsUndefined(argv[3])) { + struct rgba color = js2color(js,argv[3]); + SDL_SetTextureColorMod(tex, color.r, color.g, color.b); + } + if (JS_IsUndefined(argv[2])) + SDL_RenderTexture(renderer,tex,NULL,&dst); + else { + + rect src = js2rect(js,argv[2]); + + SDL_RenderTexture(renderer,tex,&src,&dst); + } +) + +JSC_CCALL(renderer_tile, + SDL_Renderer *renderer = js2SDL_Renderer(js,self); + if (!renderer) return JS_ThrowTypeError(js,"self was not a renderer"); + SDL_Texture *tex = js2SDL_Texture(js,argv[0]); + if (!tex) return JS_ThrowTypeError(js,"first argument was not a texture"); + rect dst = js2rect(js,argv[1]); + if (!dst.w) dst.w = tex->w; + if (!dst.h) dst.h = tex->h; + float scale = js2number(js,argv[3]); + if (!scale) scale = 1; + if (JS_IsUndefined(argv[2])) + SDL_RenderTextureTiled(renderer,tex,NULL,scale, &dst); + else { + rect src = js2rect(js,argv[2]); + SDL_RenderTextureTiled(renderer,tex,&src,scale, &dst); + } +) + +JSC_CCALL(renderer_9slice, + SDL_Renderer *renderer = js2SDL_Renderer(js,self); + SDL_Texture *tex = js2SDL_Texture(js,argv[0]); + rect *dst, *src = NULL; + lrtb bounds = js2lrtb(js,argv[2]); + +) + +JSC_CCALL(renderer_get_image, + SDL_Renderer *r = js2SDL_Renderer(js,self); + SDL_Surface *surf = NULL; + if (!JS_IsUndefined(argv[0])) { + rect rect = js2rect(js,argv[0]); + surf = SDL_RenderReadPixels(r,&rect); + } else + surf = SDL_RenderReadPixels(r,NULL); + if (!surf) return JS_ThrowReferenceError(js, "could not make surface from renderer"); + return SDL_Surface2js(js,surf); +) + +JSC_SCALL(renderer_fasttext, + SDL_Renderer *r = js2SDL_Renderer(js,self); + if (!JS_IsUndefined(argv[2])) { + struct rgba color = js2color(js,argv[2]); + SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a); + } + HMM_Vec2 pos = js2vec2(js,argv[1]); + pos.y *= -1; + pos.y += logical.y; + SDL_RenderDebugText(r, pos.x, pos.y, str); +) + +JSC_CCALL(renderer_line, + SDL_Renderer *r = js2SDL_Renderer(js,self); + if (!JS_IsUndefined(argv[1])) { + struct rgba color = js2color(js,argv[1]); + SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a); + } + + if (JS_IsArray(js,argv[0])) { + int len = js_arrlen(js,argv[0]); + HMM_Vec2 points[len]; + assert(sizeof(HMM_Vec2) == sizeof(SDL_FPoint)); + for (int i = 0; i < len; i++) { + JSValue val = JS_GetPropertyUint32(js,argv[0],i); + points[i] = js2vec2(js,val); + JS_FreeValue(js,val); + } + SDL_RenderLines(r,points,len); + } +) + +JSC_CCALL(renderer_point, + SDL_Renderer *r = js2SDL_Renderer(js,self); + if (!JS_IsUndefined(argv[1])) { + struct rgba color = js2color(js,argv[1]); + SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a); + } + + if (JS_IsArray(js,argv[0])) { + int len = js_arrlen(js,argv[0]); + HMM_Vec2 points[len]; + assert(sizeof(HMM_Vec2) ==sizeof(SDL_FPoint)); + for (int i = 0; i < len; i++) { + JSValue val = JS_GetPropertyUint32(js,argv[0],i); + points[i] = js2vec2(js,val); + JS_FreeValue(js,val); + } + SDL_RenderPoints(r, points, len); + return JS_UNDEFINED; + } + + HMM_Vec2 point = js2vec2(js,argv[0]); + SDL_RenderPoint(r,point.x,point.y); +) + +// Function to translate a list of 2D points +void Translate2DPoints(HMM_Vec2 *points, int count, HMM_Vec3 position, HMM_Quat rotation, HMM_Vec3 scale) { + // Precompute the 2D rotation matrix from the quaternion + float xx = rotation.x * rotation.x; + float yy = rotation.y * rotation.y; + float zz = rotation.z * rotation.z; + float xy = rotation.x * rotation.y; + float xz = rotation.x * rotation.z; + float yz = rotation.y * rotation.z; + float xw = rotation.x * rotation.w; + float yw = rotation.y * rotation.w; + float zw = rotation.z * rotation.w; + + // Extract 2D affine rotation and scaling + float m00 = (1.0f - 2.0f * (yy + zz)) * scale.x; // Row 1, Column 1 + float m01 = (2.0f * (xy + zw)) * scale.y; // Row 1, Column 2 + float m10 = (2.0f * (xy - zw)) * scale.x; // Row 2, Column 1 + float m11 = (1.0f - 2.0f * (xx + zz)) * scale.y; // Row 2, Column 2 + + // Translation components (ignore the z position) + float tx = position.x; + float ty = position.y; + + // Transform each point + for (int i = 0; i < count; ++i) { + HMM_Vec2 p = points[i]; + points[i].x = m00 * p.x + m01 * p.y + tx; + points[i].y = m10 * p.x + m11 * p.y + ty; + } +} + +// Should take a single struct with pos, color, uv, and indices arrays +JSC_CCALL(renderer_geometry, + SDL_Renderer *r = js2SDL_Renderer(js,self); + JSValue pos = JS_GetPropertyStr(js,argv[1], "pos"); + JSValue color = JS_GetPropertyStr(js,argv[1], "color"); + JSValue uv = JS_GetPropertyStr(js,argv[1], "uv"); + JSValue indices = JS_GetPropertyStr(js,argv[1], "indices"); + int vertices = js_getnum_str(js, argv[1], "vertices"); + int count = js_getnum_str(js, argv[1], "count"); + + size_t pos_stride, indices_stride, uv_stride, color_stride; + void *posdata = get_gpu_buffer(js,pos, &pos_stride); + void *idxdata = get_gpu_buffer(js,indices, &indices_stride); + void *uvdata = get_gpu_buffer(js,uv, &uv_stride); + void *colordata = get_gpu_buffer(js,color,&color_stride); + + SDL_Texture *tex = js2SDL_Texture(js,argv[0]); + + HMM_Vec2 *trans_pos = malloc(vertices*sizeof(HMM_Vec2)); + memcpy(trans_pos,posdata, sizeof(HMM_Vec2)*vertices); + + for (int i = 0; i < vertices; i++) { + trans_pos[i].x -= campos.x; + trans_pos[i].y -= campos.y; + } + + if (!SDL_RenderGeometryRaw(r, tex, trans_pos, pos_stride,colordata,color_stride,uvdata, uv_stride, vertices, idxdata, count, indices_stride)) + ret = JS_ThrowReferenceError(js, SDL_GetError()); + + free(trans_pos); + + JS_FreeValue(js,pos); + JS_FreeValue(js,color); + JS_FreeValue(js,uv); + JS_FreeValue(js,indices); +) + +JSC_CCALL(renderer_logical_size, + SDL_Renderer *r = js2SDL_Renderer(js,self); + HMM_Vec2 v = js2vec2(js,argv[0]); + logical = v; + SDL_SetRenderLogicalPresentation(r,v.x,v.y,SDL_LOGICAL_PRESENTATION_LETTERBOX); +) + +JSC_CCALL(renderer_viewport, + SDL_Renderer *r = js2SDL_Renderer(js,self); + if (JS_IsUndefined(argv[0])) + SDL_SetRenderViewport(r,NULL); + else { + rect view = js2rect(js,argv[0]); + SDL_SetRenderViewport(r,&view); + } +) + +JSC_CCALL(renderer_clip, + SDL_Renderer *r = js2SDL_Renderer(js,self); + if (JS_IsUndefined(argv[0])) + SDL_SetRenderClipRect(r,NULL); + else { + rect view = js2rect(js,argv[0]); + SDL_SetRenderClipRect(r,&view); + } +) + +JSC_CCALL(renderer_scale, + SDL_Renderer *r = js2SDL_Renderer(js,self); + HMM_Vec2 v = js2vec2(js,argv[0]); + SDL_SetRenderScale(r, v.x, v.y); +) + +JSC_CCALL(renderer_campos, + campos = js2vec2(js,argv[0]); +) + +JSC_CCALL(renderer_vsync, + SDL_Renderer *r = js2SDL_Renderer(js,self); + SDL_SetRenderVSync(r,js2number(js,argv[0])); +) + +JSC_CCALL(renderer_coords, + SDL_Renderer *r = js2SDL_Renderer(js,self); + HMM_Vec2 pos, coord; + pos = js2vec2(js,argv[0]); + SDL_RenderCoordinatesFromWindow(r,pos.x,pos.y, &coord.x, &coord.y); + return vec22js(js,coord); +) + +static const JSCFunctionListEntry js_SDL_Renderer_funcs[] = { + MIST_FUNC_DEF(SDL_Renderer, draw_color, 1), + MIST_FUNC_DEF(SDL_Renderer, present, 0), + MIST_FUNC_DEF(SDL_Renderer, clear, 0), + MIST_FUNC_DEF(SDL_Renderer, rect, 2), + MIST_FUNC_DEF(SDL_Renderer, fillrect, 2), + MIST_FUNC_DEF(renderer, line, 2), + MIST_FUNC_DEF(renderer, point, 2), + MIST_FUNC_DEF(renderer, load_texture, 1), + MIST_FUNC_DEF(renderer, texture, 4), + MIST_FUNC_DEF(renderer, 9slice, 4), + MIST_FUNC_DEF(renderer, tile, 4), + MIST_FUNC_DEF(renderer, get_image, 1), + MIST_FUNC_DEF(renderer, fasttext, 2), + MIST_FUNC_DEF(renderer, geometry, 2), + MIST_FUNC_DEF(renderer, scale, 1), + MIST_FUNC_DEF(renderer, campos, 1), + MIST_FUNC_DEF(renderer,logical_size,1), + MIST_FUNC_DEF(renderer,viewport,1), + MIST_FUNC_DEF(renderer,clip,1), + MIST_FUNC_DEF(renderer,vsync,1), + MIST_FUNC_DEF(renderer, coords, 1), +}; + +static const JSCFunctionListEntry js_SDL_Surface_funcs[] = {}; + +JSC_CCALL(texture_mode, + SDL_Texture *tex = js2SDL_Texture(js,self); + SDL_SetTextureScaleMode(tex,js2number(js,argv[0])); +) + +static const JSCFunctionListEntry js_SDL_Texture_funcs[] = { + MIST_FUNC_DEF(texture, mode, 1), +}; + +JSC_CCALL(input_mouse_lock, SDL_CaptureMouse(JS_ToBool(js,argv[0]))) +JSC_CCALL(input_mouse_show, + if (JS_ToBool(js,argv[0])) + SDL_ShowCursor(); + else + SDL_HideCursor(); +) static const JSCFunctionListEntry js_input_funcs[] = { - MIST_FUNC_DEF(input, show_keyboard, 1), - MIST_FUNC_DEF(input, keyboard_shown, 0), - MIST_FUNC_DEF(input, mouse_cursor, 1), MIST_FUNC_DEF(input, mouse_show, 1), MIST_FUNC_DEF(input, mouse_lock, 1), }; @@ -1678,9 +1840,6 @@ static const JSCFunctionListEntry js_prosperon_funcs[] = { MIST_FUNC_DEF(prosperon, guid, 0), }; -static const JSCFunctionListEntry js_sg_buffer_funcs[] = { -}; - JSC_CCALL(time_now, struct timeval ct; gettimeofday(&ct, NULL); @@ -1713,8 +1872,6 @@ static const JSCFunctionListEntry js_console_funcs[] = { MIST_FUNC_DEF(console,log,1), }; -JSC_CCALL(profile_now, return number2js(js,stm_now())) - static JSValue instr_v = JS_UNDEFINED; int iiihandle(JSRuntime *rt, void *data) { @@ -1738,7 +1895,7 @@ JSC_CCALL(profile_gather_stop, JSC_CCALL(profile_best_t, char* result[50]; - double seconds = stm_sec(js2number(js,argv[0])); + double seconds = SDL_GetTicksNS()/1000000000.f; if (seconds < 1e-6) snprintf(result, 50, "%.2f ns", seconds * 1e9); else if (seconds < 1e-3) @@ -1751,7 +1908,7 @@ JSC_CCALL(profile_best_t, ret = JS_NewString(js,result); ) -JSC_CCALL(profile_secs, return number2js(js,stm_sec(js2number(js,argv[0]))); ) +JSC_CCALL(profile_now, return number2js(js, SDL_GetTicksNS()/1000000000.f)) static const JSCFunctionListEntry js_profile_funcs[] = { MIST_FUNC_DEF(profile,now,0), @@ -1759,7 +1916,6 @@ static const JSCFunctionListEntry js_profile_funcs[] = { MIST_FUNC_DEF(profile,gather,2), MIST_FUNC_DEF(profile,gather_rate,1), MIST_FUNC_DEF(profile,gather_stop,0), - MIST_FUNC_DEF(profile,secs,1), }; JSC_CCALL(debug_stack_depth, return number2js(js,js_debugger_stack_depth(js))) @@ -1779,235 +1935,154 @@ static const JSCFunctionListEntry js_debug_funcs[] = { MIST_FUNC_DEF(debug, dump_obj, 1), }; -#ifdef __WIN32 -#include -#include - -void list_files(const char *path, JSContext *js, JSValue v, int *n) { - WIN32_FIND_DATA ffd; - HANDLE hFind = INVALID_HANDLE_VALUE; - char searchPath[MAX_PATH]; - - // Prepare the path for search - snprintf(searchPath, sizeof(searchPath), "%s/*", path); - - hFind = FindFirstFileEx(searchPath, FindExInfoStandard, &ffd, FindExSearchLimitToDirectories, NULL, 0); - if (hFind == INVALID_HANDLE_VALUE) { - return; - } - - do { - if (strcmp(ffd.cFileName, ".") != 0 && strcmp(ffd.cFileName, "..") != 0) { - char filePath[MAX_PATH]; - snprintf(filePath, sizeof(filePath), "%s/%s", path, ffd.cFileName); - - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - // If it's a directory, recurse into it -// printf("Directory: %s\n", filePath); - list_files(filePath, js, v, n); - } else { - JS_SetPropertyUint32(js, v, *n, JS_NewString(js, filePath+2)); - *n = *n+1; - // If it's a file, print it -// printf("File: %s\n", filePath); - } - } - } while (FindNextFile(hFind, &ffd) != 0); - - FindClose(hFind); -} -#else -static void list_files(const char *path, JSContext *js, JSValue v, int *n) -{ - tinydir_dir dir; - tinydir_open(&dir, path); - do { - tinydir_file file; - tinydir_readfile(&dir, &file); - if (file.is_dir) { - if (!strcmp(file.name, ".") || !strcmp(file.name, "..")) continue; - list_files(file.path, js, v, n); - } else { - JS_SetPropertyUint32(js, v, *n, JS_NewString(js, file.path+2)); - *n = *n+1; - } - } while (!tinydir_next(&dir)); - - tinydir_close(&dir); -} -#endif -JSC_CCALL(io_ls, - JSValue strarr = JS_NewArray(js); - int i = 0; - list_files(".", js, strarr, &i); - return strarr; +JSC_SCALL(io_rm, + if (!PHYSFS_delete(str)) ret = JS_ThrowReferenceError(js,PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); +) +JSC_SCALL(io_mkdir, + if (!PHYSFS_mkdir(str)) ret = JS_ThrowReferenceError(js,PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); ) -JSC_SSCALL(io_mv, ret = number2js(js,rename(str,str2))) -JSC_SCALL(io_chdir, ret = number2js(js,chdir(str))) -JSC_SCALL(io_rm, ret = number2js(js,remove(str))) -JSC_SCALL(io_mkdir, ret = number2js(js,mkdir(str,0777))) -// glob sprites/*.png -// glob sprite/**/*.png -// pattern: sprites/fool.png -// glob sprites/fool.png -#include "wildmatch.h" -JSC_SSCALL(io_glob, - if (wildmatch(str, str2, WM_PATHNAME | WM_PERIOD | WM_WILDSTAR) == WM_MATCH) - return JS_NewBool(js,1); +JSC_SCALL(io_exists, ret = JS_NewBool(js,PHYSFS_exists(str)); ) + +JSC_SCALL(io_stat, + PHYSFS_Stat stat; + if (!PHYSFS_stat(str, &stat)) + return JS_ThrowReferenceError(js, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); + + ret = JS_NewObject(js); + JS_SetPropertyStr(js,ret,"filesize", number2js(js,stat.filesize)); + JS_SetPropertyStr(js,ret,"modtime", number2js(js,stat.modtime)); + JS_SetPropertyStr(js,ret,"createtime", number2js(js,stat.createtime)); + JS_SetPropertyStr(js,ret,"accesstime", number2js(js,stat.accesstime)); +) + +JSC_SCALL(io_slurp, + PHYSFS_File *f = PHYSFS_openRead(str); + if (!f) { + ret = JS_ThrowReferenceError(js,"physfs error when slurping %s: %s", str, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); + goto END; + } + PHYSFS_Stat stat; + PHYSFS_stat(str,&stat); + void *data = malloc(stat.filesize); + PHYSFS_readBytes(f,data,stat.filesize); + PHYSFS_close(f); + if (JS_ToBool(js,argv[1])) + ret = JS_NewStringLen(js,data, stat.filesize); else - return JS_NewBool(js, 0); + ret = JS_NewArrayBufferCopy(js,data,stat.filesize); + + END: ) -#include -#include -#include - -#ifdef _WIN32 -#include -#else -#include -#include -#include -#include -#endif - -JSValue js_io_slurp(JSContext *js, JSValue self, int argc, JSValue *argv) { - const char *file = JS_ToCString(js, argv[0]); - if (!file) - return JS_EXCEPTION; - - size_t fsize; - void *slurp = NULL; - -#ifdef _WIN32 - // Windows file mapping - HANDLE hFile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - JS_FreeCString(js, file); - return JS_UNDEFINED; - } - - LARGE_INTEGER fileSize; - if (!GetFileSizeEx(hFile, &fileSize)) { - CloseHandle(hFile); - JS_FreeCString(js, file); - return JS_UNDEFINED; - } - - fsize = (size_t)fileSize.QuadPart; - HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (hMapping == NULL) { - CloseHandle(hFile); - JS_FreeCString(js, file); - return JS_UNDEFINED; - } - - slurp = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); - CloseHandle(hMapping); - CloseHandle(hFile); - - if (slurp == NULL) { - JS_FreeCString(js, file); - return JS_UNDEFINED; - } - -#else - // POSIX mmap - int fd = open(file, O_RDONLY); - if (fd < 0) { - JS_FreeCString(js, file); - return JS_UNDEFINED; - } - - struct stat sb; - if (fstat(fd, &sb) == -1) { - close(fd); - JS_FreeCString(js, file); - return JS_UNDEFINED; - } - - fsize = sb.st_size; - slurp = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0); - close(fd); - - if (slurp == MAP_FAILED) { - JS_FreeCString(js, file); - return JS_UNDEFINED; - } -#endif - - JSValue ret; - if (JS_ToBool(js, argv[1])) { - // Return as string - ret = JS_NewStringLen(js, slurp, fsize); - } else { - // Return as ArrayBuffer - ret = JS_NewArrayBufferCopy(js, slurp, fsize); - } - -#ifdef _WIN32 - // Unmap on Windows - UnmapViewOfFile(slurp); -#else - // Unmap on POSIX - munmap(slurp, fsize); -#endif - - JS_FreeCString(js, file); - return ret; -} - -JSValue js_io_slurpwrite(JSContext *js, JSValue self, int argc, JSValue *argv) -{ - const char *f = JS_ToCString(js, argv[0]); - FILE *file = fopen(f,"wb"); - if (!file) return JS_ThrowReferenceError(js, "could not open file for writing at %s", f); +JSC_SCALL(io_slurpwrite, + PHYSFS_File *f = PHYSFS_openWrite(str); + if (!f) { + ret = JS_ThrowReferenceError(js,PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); + goto END; + } size_t len; - JSValue ret; - if (JS_IsString(argv[1])) { - const char *data = JS_ToCStringLen(js, &len, argv[1]); - ret = number2js(js, fwrite(data, len, 1, file)); - JS_FreeCString(js,data); - fclose(file); - } else { - unsigned char *data = JS_GetArrayBuffer(js, &len, argv[1]); - ret = number2js(js,fwrite(data,len,1,file)); - fclose(file); + unsigned char *data; + if (JS_IsString(argv[1])) + data = JS_ToCStringLen(js,&len,argv[1]); + else + data = JS_GetArrayBuffer(js,&len, argv[1]); + + size_t wrote = PHYSFS_writeBytes(f,data, len); + PHYSFS_close(f); + if (wrote == -1 || wrote < len) + ret = JS_ThrowReferenceError(js,PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); + + END: +) + +JSC_SCALL(io_mount, + if (!PHYSFS_mount(str,NULL,0)) ret = JS_ThrowReferenceError(js,PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); +) + +JSC_SCALL(io_unmount, + if (!PHYSFS_unmount(str)) ret = JS_ThrowReferenceError(js,PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); +) + +JSC_SCALL(io_writepath, + if (!PHYSFS_setWriteDir(str)) ret = JS_ThrowReferenceError(js,PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); +) + +struct globdata { + JSContext *js; + JSValue arr; + char **globs; + int idx; +}; + +int globfs_cb(struct globdata *data, char *dir, char *file) +{ + int needfree = 0; + char *path; + if (dir[0] == 0) path = file; + else { + path = malloc(strlen(dir) + strlen(file) + 2); + path[0] = 0; + strcat(path,dir); + strcat(path,"/"); + strcat(path,file); + needfree = 1; } - return ret; + char **glob = data->globs; + while (*glob != NULL) { + if (wildmatch(*glob, path, WM_PATHNAME | WM_PERIOD | WM_WILDSTAR) == WM_MATCH) + goto END; + *glob++; + } + + if (PHYSFS_isDirectory(path)) { + PHYSFS_enumerate(path, globfs_cb, data); + goto END; + } + + JS_SetPropertyUint32(data->js, data->arr, data->idx++, JS_NewString(data->js,path)); + + END: + if (needfree) free(path); + return 1; } -JSValue js_io_chmod(JSContext *js, JSValue self, int argc, JSValue *argv) -{ - const char *f = JS_ToCString(js, argv[0]); - int mod = js2number(js,argv[1]); - chmod(f, mod); - return JS_UNDEFINED; -} +JSC_CCALL(io_globfs, + ret = JS_NewArray(js); + struct globdata data; + data.js = js; + data.arr = ret; + data.idx = 0; + int globs_len = js_arrlen(js,argv[0]); + char *globs[globs_len+1]; + for (int i = 0; i < globs_len; i++) { + JSValue g = JS_GetPropertyUint32(js,argv[0],i); + globs[i] = JS_ToCString(js,g); + JS_FreeValue(js,g); + } + globs[globs_len] = NULL; + data.globs = globs; -JSC_SCALL(io_mod, - #ifndef __EMSCRIPTEN__ - struct stat attr; - if (!stat(str,&attr)) - ret = number2js(js,attr.st_mtime); - else - return JS_UNDEFINED;//JS_ThrowReferenceError(js, "could not get file attributes of %s", str); - #endif + PHYSFS_enumerate("", globfs_cb, &data); + + return data.arr; ) +JSC_CCALL(io_basedir, return JS_NewString(js,PHYSFS_getBaseDir())) + static const JSCFunctionListEntry js_io_funcs[] = { - MIST_FUNC_DEF(io, mv, 2), - MIST_FUNC_DEF(io, ls, 0), MIST_FUNC_DEF(io, rm, 1), - MIST_FUNC_DEF(io, chdir, 1), MIST_FUNC_DEF(io, mkdir, 1), - MIST_FUNC_DEF(io, chmod, 2), - MIST_FUNC_DEF(io, slurp, 2), - MIST_FUNC_DEF(io, slurpwrite, 2), - MIST_FUNC_DEF(io, mod,1), - MIST_FUNC_DEF(io, glob, 2), + MIST_FUNC_DEF(io,stat,1), + MIST_FUNC_DEF(io, globfs, 1), + MIST_FUNC_DEF(io, exists, 1), + MIST_FUNC_DEF(io, mount, 1), + MIST_FUNC_DEF(io,unmount,1), + MIST_FUNC_DEF(io,slurp,2), + MIST_FUNC_DEF(io,slurpwrite,2), + MIST_FUNC_DEF(io,writepath, 1), + MIST_FUNC_DEF(io,basedir, 0), }; JSC_GETSET(transform, pos, vec3) @@ -2122,13 +2197,13 @@ JSC_GET(texture, vram, number) JSC_SCALL(texture_save, texture_save(js2texture(js,self), str)); -JSC_CCALL(texture_blit, - texture_blit(js2texture(js,self), js2texture(js,argv[0]), js2rect(js,argv[1]), js2rect(js,argv[2]), JS_ToBool(js,argv[3])); +JSC_CCALL(texture_blit, +// texture_blit(js2texture(js,self), js2texture(js,argv[0]), js2rect(js,argv[1]), js2rect(js,argv[2]), JS_ToBool(js,argv[3])); ) JSC_CCALL(texture_getid, texture *tex = js2texture(js,self); - return number2js(js,tex->id.id); + return number2js(js,(int)tex->id); ) JSC_CCALL(texture_inram, return JS_NewBool(js,(int)js2texture(js,self)->data)); @@ -2151,7 +2226,7 @@ JSC_CCALL(texture_write_pixel, ) JSC_CCALL(texture_dup, - ret = texture2js(js,texture_dup(js2texture(js,self))); +// ret = texture2js(js,texture_dup(js2texture(js,self))); ) JSC_CCALL(texture_scale, @@ -2159,7 +2234,10 @@ JSC_CCALL(texture_scale, ) JSC_CCALL(texture_load_gpu, - texture_load_gpu(js2texture(js,self)); + return JS_UNDEFINED; + SDL_Renderer *renderer = js2SDL_Renderer(js,self); + SDL_Surface *surface = js2SDL_Surface(js,argv[0]); + SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface); ) JSC_CCALL(texture_offload, @@ -2231,13 +2309,12 @@ static const JSCFunctionListEntry js_performance_funcs[] = { MIST_FUNC_DEF(performance, call_fn_n, 3) }; -JSC_CCALL(geometry_rect_intersect, +JSC_CCALL(geometry_rect_intersection, rect a = js2rect(js,argv[0]); rect b = js2rect(js,argv[1]); - return JS_NewBool(js,a.x < (b.x+b.w) && - (a.x + a.w) > b.x && - a.y < (b.y + b.h) && - (a.y + a.h) > b.y ); + rect c; + SDL_GetRectIntersectionFloat(&a, &b, &c); + return rect2js(js,c); ) JSC_CCALL(geometry_rect_inside, @@ -2287,13 +2364,12 @@ JSC_CCALL(geometry_rect_pos, JSC_CCALL(geometry_rect_move, rect r = js2rect(js,argv[0]); HMM_Vec2 move = js2vec2(js,argv[1]); - r.x += move.x; - r.y += move.y; + cblas_saxpy(2, 1.0f, move.e, 1, &r, 1); return rect2js(js,r); ) static const JSCFunctionListEntry js_geometry_funcs[] = { - MIST_FUNC_DEF(geometry, rect_intersect, 2), + MIST_FUNC_DEF(geometry, rect_intersection, 2), MIST_FUNC_DEF(geometry, rect_inside, 2), MIST_FUNC_DEF(geometry, rect_random, 1), MIST_FUNC_DEF(geometry, cwh2rect, 2), @@ -2523,10 +2599,33 @@ JSC_CCALL(os_make_texture, void *raw = JS_GetArrayBuffer(js, &len, argv[0]); if (!raw) return JS_ThrowReferenceError(js, "could not load texture with array buffer"); - texture *tex = texture_fromdata(raw, len); - if (!tex) return JS_ThrowReferenceError(js, "unable to make texture from the given array buffer"); + struct texture *tex = calloc(1, sizeof(*tex)); - ret = texture2js(js,tex); + int n, width, height; + void *data = stbi_load_from_memory(raw, len, &width, &height, &n, 0); + + if (data == NULL) + return JS_ThrowReferenceError(js, "no known image type from pixel data"); + + int FMT = 0; + if (n == 4) + FMT = SDL_PIXELFORMAT_RGBA32; + else if (n == 3) + FMT = SDL_PIXELFORMAT_RGB24; + else { + free(data); + return JS_ThrowReferenceError(js, "unknown pixel format"); + } + + SDL_Surface *surf = SDL_CreateSurfaceFrom(width,height,FMT, data, width*n); + if (!surf) { + free(data); + return JS_ThrowReferenceError(js, SDL_GetError()); + } + + ret = SDL_Surface2js(js,surf); + JS_SetProperty(js,ret,width_atom,number2js(js,surf->w)); + JS_SetProperty(js,ret,height_atom,number2js(js,surf->h)); ) JSC_CCALL(os_make_gif, @@ -2647,7 +2746,8 @@ JSC_CCALL(os_make_font, font *f = MakeFont(data, len, js2number(js,argv[1])); if (!f) return JS_ThrowReferenceError(js, "could not create font"); ret = font2js(js,f); - JS_SetPropertyStr(js, ret, "texture", texture2js(js,f->texture)); + JS_SetPropertyStr(js, ret, "surface", SDL_Surface2js(js,f->surface)); + printf("texture is %dx%d at %p\n", f->surface->w, f->surface->h, f->surface); ) JSC_CCALL(os_make_transform, return transform2js(js,make_transform())) @@ -2662,11 +2762,11 @@ JSC_SCALL(os_gltf_buffer, cgltf_result result = cgltf_parse_file(&options, str, &data); result = cgltf_load_buffers(&options, data, str); - sg_buffer *b = malloc(sizeof(*b)); - *b = accessor2buffer(&data->accessors[buffer_idx], type); + SDL_GPUBuffer *b = SDL_CreateGPUBuffer(NULL,NULL); +// *b = accessor2buffer(&data->accessors[buffer_idx], type); cgltf_free(data); - ret = sg_buffer2js(js,b); +// ret = sg_buffer2js(js,b); ) JSC_SCALL(os_gltf_skin, @@ -2691,7 +2791,7 @@ JSC_CCALL(os_make_buffer, float *b = malloc(sizeof(float)*js_arrlen(js,argv[0])); for (int i = 0; i < js_arrlen(js,argv[0]); i++) b[i] = js_getnum_uint32(js, argv[0],i); - +/* sg_buffer *p = malloc(sizeof(sg_buffer)); switch(type) { @@ -2710,17 +2810,21 @@ JSC_CCALL(os_make_buffer, } free(b); - return sg_buffer2js(js,p); + return sg_buffer2js(js,p);*/ +) + +JSC_CCALL(os_make_color_buffer, + int count = js2number(js,argv[1]); + HMM_Vec4 color = js2vec4(js,argv[0]); + HMM_Vec4 *buffer = malloc(sizeof(HMM_Vec4) * count); + for (int i = 0; i < count; i++) + memcpy(buffer+i, &color, sizeof(HMM_Vec4)); + ret = make_gpu_buffer(js,buffer,sizeof(HMM_Vec4)*count,JS_TYPED_ARRAY_FLOAT32,4,0); ) JSC_CCALL(os_make_line_prim, JSValue prim = JS_NewObject(js); HMM_Vec2 *v = js2cpvec2arr(js,argv[0]); - parsl_position par_v[arrlen(v)]; - for (int i = 0; i < arrlen(v); i++) { - par_v[i].x = v[i].x; - par_v[i].y = v[i].y; - } parsl_context *par_ctx = parsl_create_context((parsl_config){ .thickness = js2number(js,argv[1]), @@ -2733,43 +2837,33 @@ JSC_CCALL(os_make_line_prim, parsl_mesh *m = parsl_mesh_from_lines(par_ctx, (parsl_spine_list){ .num_vertices = arrlen(v), .num_spines = 1, - .vertices = par_v, + .vertices = v, .spine_lengths = spine_lens, .closed = JS_ToBool(js,argv[3]) }); - HMM_Vec3 a_pos[m->num_vertices]; + + JS_SetPropertyStr(js, prim, "pos", make_gpu_buffer(js,m->positions,sizeof(*m->positions)*m->num_vertices, JS_TYPED_ARRAY_FLOAT32, 2,1)); - for (int i = 0; i < m->num_vertices; i++) { - a_pos[i].x = m->positions[i].x; - a_pos[i].y = m->positions[i].y; - a_pos[i].z = 0; - } - - sg_buffer *pos = malloc(sizeof(*pos)); - *pos = sg_make_buffer(&(sg_buffer_desc){ - .data = SG_RANGE(a_pos), - }); - JS_SetPropertyStr(js, prim, "pos", sg_buffer2js(js,pos)); - JS_SetPropertyStr(js, prim, "count", number2js(js,m->num_triangles*3)); - sg_buffer *idx = malloc(sizeof(*idx)); - *idx = par_idx_buffer(m->triangle_indices, m->num_triangles*3); - JS_SetPropertyStr(js, prim, "index", sg_buffer2js(js,idx)); + JS_SetPropertyStr(js, prim, "indices", make_gpu_buffer(js,m->triangle_indices,sizeof(*m->triangle_indices)*m->num_triangles*3, JS_TYPED_ARRAY_UINT32, 1,1)); float uv[m->num_vertices*2]; for (int i = 0; i < m->num_vertices; i++) { uv[i*2] = m->annotations[i].u_along_curve; uv[i*2+1] = m->annotations[i].v_across_curve; } - sg_buffer *buv = malloc(sizeof(*buv)); - *buv = texcoord_floats(uv, m->num_vertices*2); - JS_SetPropertyStr(js, prim, "uv", sg_buffer2js(js,buv)); + + JS_SetPropertyStr(js, prim, "uv", make_gpu_buffer(js, uv, sizeof(uv), JS_TYPED_ARRAY_FLOAT32,2,1)); + JS_SetPropertyStr(js,prim,"vertices", number2js(js,m->num_vertices)); + JS_SetPropertyStr(js,prim,"count", number2js(js,m->num_triangles*3)); + + parsl_destroy_context(par_ctx); return prim; ) JSValue parmesh2js(JSContext *js,par_shapes_mesh *m) { - JSValue obj = JS_NewObject(js); +/* JSValue obj = JS_NewObject(js); sg_buffer *pos = malloc(sizeof(*pos)); *pos = float_buffer(m->points, 3*m->npoints); JS_SetPropertyStr(js, obj, "pos", sg_buffer2js(js,pos)); @@ -2800,6 +2894,7 @@ JSValue parmesh2js(JSContext *js,par_shapes_mesh *m) par_shapes_free_mesh(m); return obj; +*/ } JSC_CCALL(os_make_cylinder, @@ -2844,7 +2939,7 @@ JSC_CCALL(os_make_video, datastream *ds = ds_openvideo(data, len); ret = datastream2js(js,ds); texture *t = malloc(sizeof(texture)); - t->id = ds->img; +// t->id = ds->img; JS_SetPropertyStr(js, ret, "texture", texture2js(js,t)); ) @@ -2919,29 +3014,79 @@ JSC_SCALL(os_kill, return JS_UNDEFINED; ) -#include "glad.h" -JSC_CCALL(os_tex_data, -#ifdef SOKOL_GLCORE - texture *tex = js2texture(js, argv[0]); - sg_gl_image_info glinfo = sg_gl_query_image_info(tex->id); - glBindTexture(glinfo.tex_target, glinfo.tex[glinfo.active_slot]); - unsigned char *pixels = malloc(tex->width * tex->height * 4); - glGetTexImage(glinfo.tex_target, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - GLenum err = glGetError(); - if (err != GL_NO_ERROR) { - free(pixels); - return JS_ThrowReferenceError(js, "could not pull pixel data"); +JSC_CCALL(os_make_sprite_mesh, + JSValue sprites = argv[0]; + JSValue old = argv[1]; + size_t quads = js_arrlen(js,argv[0]); + size_t verts = quads*4; + size_t count = quads*6; + + HMM_Vec2 *posdata = malloc(sizeof(*posdata)*verts); + HMM_Vec2 *uvdata = malloc(sizeof(*uvdata)*verts); + HMM_Vec4 *colordata = malloc(sizeof(*colordata)*verts); + + for (int i = 0; i < quads; i++) { + JSValue sub = JS_GetPropertyUint32(js,sprites,i); + JSValue jsdst = JS_GetProperty(js,sub,dst_atom); + JSValue jssrc = JS_GetProperty(js,sub,src_atom); + JSValue jscolor = JS_GetProperty(js,sub,color_atom); + HMM_Vec4 color; + rect dst = js2rect(js,jsdst); + + rect src; + if (JS_IsUndefined(jssrc)) + src = (rect){.x = 0, .y = 0, .w = 1, .h = 1}; + else + src = js2rect(js,jssrc); + + if (JS_IsUndefined(jscolor)) + color = (HMM_Vec4){1,1,1,1}; + else + color = js2vec4(js,jscolor); + + // Calculate the base index for the current quad + size_t base = i * 4; + + // Define the four corners of the destination rectangle + posdata[base + 0] = (HMM_Vec2){ dst.x, dst.y + dst.h }; + posdata[base + 1] = (HMM_Vec2){ dst.x + dst.w, dst.y + dst.h }; + posdata[base + 2] = (HMM_Vec2){ dst.x, dst.y }; + posdata[base + 3] = (HMM_Vec2){ dst.x + dst.w, dst.y }; + + // Define the UV coordinates based on the source rectangle + uvdata[base + 0] = (HMM_Vec2){ src.x, src.y + src.h }; + uvdata[base + 1] = (HMM_Vec2){ src.x + src.w, src.y + src.h }; + uvdata[base + 2] = (HMM_Vec2){ src.x, src.y }; + uvdata[base + 3] = (HMM_Vec2){ src.x + src.w, src.y }; + + cblas_scopy(4, color.e, 1, &(colordata[base+0].x),1); + cblas_scopy(4, color.e, 1, &(colordata[base+1].x),1); + cblas_scopy(4, color.e, 1, &(colordata[base+2].x),1); + cblas_scopy(4, color.e, 1, &(colordata[base+3].x),1); +/* colordata[base + 0] = color; + colordata[base + 1] = color; + colordata[base + 2] = color; + colordata[base + 3] = color; + */ + JS_FreeValue(js,sub); + JS_FreeValue(js,jscolor); + JS_FreeValue(js,jsdst); + JS_FreeValue(js,jssrc); } - glBindTexture(glinfo.tex_target,0); - ret = JS_NewArrayBufferCopy(js,pixels,tex->width*tex->height*4); - free(pixels); - return ret; - #endif + + ret = JS_NewObject(js); + JS_SetProperty(js, ret, pos_atom, make_gpu_buffer(js, posdata, sizeof(*posdata) * verts, JS_TYPED_ARRAY_FLOAT32, 2, 0)); + JS_SetProperty(js, ret, uv_atom, make_gpu_buffer(js, uvdata, sizeof(*uvdata) * verts, JS_TYPED_ARRAY_FLOAT32, 2, 0)); + JS_SetProperty(js, ret, color_atom, make_gpu_buffer(js, colordata, sizeof(*colordata) * verts, JS_TYPED_ARRAY_FLOAT32, 2, 0)); + JS_SetProperty(js, ret, indices_atom, make_quad_indices_buffer(js, quads)); + JS_SetProperty(js, ret, vertices_atom, number2js(js, verts)); + JS_SetProperty(js, ret, count_atom, number2js(js, count)); ) static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, turbulence, 4), MIST_FUNC_DEF(os, fbm, 4), + MIST_FUNC_DEF(os, make_color_buffer, 2), MIST_FUNC_DEF(os, backend, 0), MIST_FUNC_DEF(os, ridge, 5), MIST_FUNC_DEF(os, perlin, 3), @@ -2974,6 +3119,8 @@ static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, make_plane, 2), MIST_FUNC_DEF(os, make_video, 1), MIST_FUNC_DEF(os, make_timer, 1), + MIST_FUNC_DEF(os, make_sprite_mesh, 2), + MIST_FUNC_DEF(os, make_text_buffer, 6), MIST_FUNC_DEF(os, update_timers, 1), MIST_FUNC_DEF(os, mem, 1), MIST_FUNC_DEF(os, mem_limit, 1), @@ -2992,7 +3139,6 @@ static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, gltf_skin, 1), MIST_FUNC_DEF(os, skin_calculate, 1), MIST_FUNC_DEF(os, kill, 1), - MIST_FUNC_DEF(os, tex_data,1), }; #define JSSTATIC(NAME, PARENT) \ @@ -3010,7 +3156,7 @@ JSValue js_tracy_use(JSContext *js); #endif #ifndef NEDITOR -JSValue js_imgui(JSContext *js); +//JSValue js_imgui(JSContext *js); JSValue js_dmon_use(JSContext *js); #endif @@ -3047,15 +3193,18 @@ static void exit_handler() } void ffi_load(JSContext *js) { - stm_setup(); /* time */ cycles = tmpfile(); quickjs_set_cycleout(cycles); JSValue globalThis = JS_GetGlobalObject(js); + QJSCLASSPREP_FUNCS(SDL_Window) + QJSCLASSPREP_FUNCS(SDL_Surface) + QJSCLASSPREP_FUNCS(SDL_Texture) + QJSCLASSPREP_FUNCS(SDL_Renderer) + QJSGLOBALCLASS(os); - QJSCLASSPREP_FUNCS(sg_buffer); QJSCLASSPREP_FUNCS(transform); // QJSCLASSPREP_FUNCS(warp_gravity); // QJSCLASSPREP_FUNCS(warp_damp); @@ -3064,6 +3213,7 @@ void ffi_load(JSContext *js) { QJSCLASSPREP_FUNCS(datastream); QJSCLASSPREP_FUNCS(timer); + QJSGLOBALCLASS(input); QJSGLOBALCLASS(io); QJSGLOBALCLASS(prosperon); @@ -3072,7 +3222,6 @@ void ffi_load(JSContext *js) { QJSGLOBALCLASS(profile); QJSGLOBALCLASS(debug); QJSGLOBALCLASS(game); - QJSGLOBALCLASS(gui); QJSGLOBALCLASS(render); QJSGLOBALCLASS(vector); QJSGLOBALCLASS(spline); @@ -3088,14 +3237,11 @@ void ffi_load(JSContext *js) { array_proto = js_getpropertystr(js,array_proto, "prototype"); JS_SetPropertyFunctionList(js, array_proto, js_array_funcs, countof(js_array_funcs)); - srand(stm_now()); - JS_SetPropertyStr(js, globalThis, "layout", js_layout_use(js)); JS_SetPropertyStr(js, globalThis, "miniz", js_miniz_use(js)); JS_SetPropertyStr(js, globalThis, "soloud", js_soloud_use(js)); JS_SetPropertyStr(js, globalThis, "chipmunk2d", js_chipmunk2d_use(js)); - #ifdef TRACY_ENABLE JS_SetPropertyStr(js, globalThis, "tracy", js_tracy_use(js)); #endif @@ -3108,8 +3254,23 @@ void ffi_load(JSContext *js) { #ifndef NEDITOR JS_SetPropertyStr(js, globalThis, "dmon", js_dmon_use(js)); - JS_SetPropertyStr(js, globalThis, "imgui", js_imgui(js)); +// JS_SetPropertyStr(js, globalThis, "imgui", js_imgui(js)); #endif - + + x_atom = JS_NewAtom(js,"x"); + y_atom = JS_NewAtom(js,"y"); + width_atom = JS_NewAtom(js,"width"); + height_atom = JS_NewAtom(js,"height"); + anchor_x_atom = JS_NewAtom(js, "anchor_x"); + anchor_y_atom = JS_NewAtom(js,"anchor_y"); + src_atom = JS_NewAtom(js,"src"); + pos_atom = JS_NewAtom(js, "pos"); + uv_atom = JS_NewAtom(js, "uv"); + color_atom = JS_NewAtom(js, "color"); + indices_atom = JS_NewAtom(js, "indices"); + vertices_atom = JS_NewAtom(js, "vertices"); + dst_atom = JS_NewAtom(js, "dst"); + count_atom = JS_NewAtom(js, "count"); + JS_FreeValue(js,globalThis); } diff --git a/source/model.c b/source/model.c index 1ac576ad..26197ea1 100644 --- a/source/model.c +++ b/source/model.c @@ -21,13 +21,11 @@ #include "texture.h" -#include "sokol/sokol_gfx.h" - #include "jsffi.h" unsigned short pack_short_tex(float c) { return c * USHRT_MAX; } -sg_buffer texcoord_floats(float *f, int n) +SDL_GPUBuffer *texcoord_floats(float *f, int n) { unsigned short packed[n]; for (int i = 0; i < n; i++) { @@ -37,43 +35,47 @@ sg_buffer texcoord_floats(float *f, int n) packed[i] = pack_short_tex(v); } - return sg_make_buffer(&(sg_buffer_desc){ +/* return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(packed), .label = "tex coord vert buffer", - }); + });*/ + return NULL; } -sg_buffer par_idx_buffer(uint32_t *p, int v) +SDL_GPUBuffer *par_idx_buffer(uint32_t *p, int v) { uint16_t idx[v]; for (int i = 0; i < v; i++) idx[i] = p[i]; - return sg_make_buffer(&(sg_buffer_desc){ +/* return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(idx), .type = SG_BUFFERTYPE_INDEXBUFFER - }); + });*/ + return NULL; } -sg_buffer float_buffer(float *f, int v) +SDL_GPUBuffer *float_buffer(float *f, int v) { - return sg_make_buffer(&(sg_buffer_desc){ + return NULL; +/* return sg_make_buffer(&(sg_buffer_desc){ .data = (sg_range){ .ptr = f, .size = sizeof(*f)*v } - }); + });*/ } -sg_buffer index_buffer(float *f, int verts) +SDL_GPUBuffer *index_buffer(float *f, int verts) { - uint16_t idxs[verts]; + return NULL; +/* uint16_t idxs[verts]; for (int i = 0; i < verts; i++) idxs[i] = f[i]; return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(idxs), .type = SG_BUFFERTYPE_INDEXBUFFER, - }); + });*/ } uint32_t pack_int10_n2(float *norm) @@ -87,40 +89,44 @@ uint32_t pack_int10_n2(float *norm) } // Pack an array of normals into -sg_buffer normal_floats(float *f, int n) +SDL_GPUBuffer *normal_floats(float *f, int n) { return float_buffer(f, n); - uint32_t packed_norms[n/3]; +/* uint32_t packed_norms[n/3]; for (int v = 0, i = 0; v < n/3; v++, i+= 3) packed_norms[v] = pack_int10_n2(f+i); return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(packed_norms), .label = "normal vert buffer", - }); + });*/ } -sg_buffer ubyten_buffer(float *f, int v) +SDL_GPUBuffer *ubyten_buffer(float *f, int v) { - unsigned char b[v]; + return NULL; +/* unsigned char b[v]; for (int i = 0; i < (v); i++) b[i] = f[i]*255; - return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)}); + return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)});*/ } -sg_buffer ubyte_buffer(float *f, int v) +SDL_GPUBuffer *ubyte_buffer(float *f, int v) { - unsigned char b[v]; + return NULL; +/* unsigned char b[v]; for (int i = 0; i < (v); i++) b[i] = f[i]; return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)}); +*/ } -sg_buffer accessor2buffer(cgltf_accessor *a, int type) +SDL_GPUBuffer *accessor2buffer(cgltf_accessor *a, int type) { - int n = cgltf_accessor_unpack_floats(a, NULL, 0); + return NULL; +/* int n = cgltf_accessor_unpack_floats(a, NULL, 0); float vs[n]; cgltf_accessor_unpack_floats(a, vs, n); @@ -150,6 +156,7 @@ sg_buffer accessor2buffer(cgltf_accessor *a, int type) .data.size = 4, .usage = SG_USAGE_STREAM }); +*/ } void packFloats(float *src, float *dest, int srcLength) { diff --git a/source/model.h b/source/model.h index 8d6195fe..42623931 100644 --- a/source/model.h +++ b/source/model.h @@ -3,7 +3,6 @@ #include "HandmadeMath.h" #include "transform.h" -#include "sokol/sokol_gfx.h" #include "gameobject.h" #include "anim.h" #include "texture.h" @@ -38,11 +37,11 @@ typedef struct skin { animation *anim; } skin; -sg_buffer accessor2buffer(cgltf_accessor *a, int type); +//sg_buffer accessor2buffer(cgltf_accessor *a, int type); skin *make_gltf_skin(cgltf_skin *skin, cgltf_data *data); void skin_calculate(skin *sk); -sg_buffer float_buffer(float *f, int v); +/*sg_buffer float_buffer(float *f, int v); sg_buffer index_buffer(float *f, int verts); sg_buffer texcoord_floats(float *f, int n); sg_buffer par_idx_buffer(uint32_t *i, int v); @@ -51,5 +50,5 @@ sg_buffer ubyten_buffer(float *f, int v); sg_buffer ubyte_buffer(float *f, int v); sg_buffer joint_buf(float *f, int v); sg_buffer weight_buf(float *f, int v); - +*/ #endif diff --git a/source/qjs_macros.h b/source/qjs_macros.h index 248a559c..50039aec 100644 --- a/source/qjs_macros.h +++ b/source/qjs_macros.h @@ -81,31 +81,27 @@ JSValue js_global_get_##ENTRY (JSContext *js, JSValue self) { \ JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue self) { \ return TYPE##2js(js,js2##ID (js, self)->ENTRY); } \ -#define QJSCLASS(TYPE)\ +#define QJSCLASS(TYPE, ...)\ static JSClassID js_##TYPE##_id;\ -static int js_##TYPE##_count = 0; \ static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\ TYPE *n = JS_GetOpaque(val, js_##TYPE##_id);\ -js_##TYPE##_count--; \ TYPE##_free(rt,n);}\ -static JSClassDef js_##TYPE##_class = {\ +static inline JSClassDef js_##TYPE##_class = {\ #TYPE,\ .finalizer = js_##TYPE##_finalizer,\ };\ -TYPE *js2##TYPE (JSContext *js, JSValue val) { \ +static inline TYPE *js2##TYPE (JSContext *js, JSValue val) { \ if (JS_IsUndefined(val)) return NULL; \ - assert(JS_GetClassID(val) == js_##TYPE##_id); \ + if (JS_GetClassID(val) != js_##TYPE##_id) return NULL; \ return JS_GetOpaque(val,js_##TYPE##_id); \ }\ -JSValue TYPE##2js(JSContext *js, TYPE *n) { \ +static inline JSValue TYPE##2js(JSContext *js, TYPE *n) { \ + __VA_ARGS__ \ JSValue j = JS_NewObjectClass(js,js_##TYPE##_id);\ JS_SetOpaque(j,n);\ - js_##TYPE##_count++; \ return j; }\ \ static JSValue js_##TYPE##_memid (JSContext *js, JSValue self) { return JS_NewString(js,"p"); } \ -static JSValue js_##TYPE##_memsize (JSContext *js, JSValue self) { return number2js(js,sizeof(TYPE)); } \ -static JSValue js_##TYPE##__count (JSContext *js, JSValue self) { return number2js(js,js_##TYPE##_count); } \ #define QJSGLOBALCLASS(NAME) \ JSValue NAME = JS_NewObject(js); \ @@ -119,8 +115,6 @@ JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\ JSValue TYPE##_proto = JS_NewObject(js); \ JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYPE##_funcs)); \ JS_SetPropertyStr(js, TYPE##_proto, "memid", JS_NewCFunction(js, &js_##TYPE##_memid, "memid", 0)); \ -JS_SetPropertyStr(js, TYPE##_proto, "memsize", JS_NewCFunction(js, &js_##TYPE##_memsize, "memsize", 0)); \ -JS_SetPropertyStr(js, TYPE##_proto, "_count", JS_NewCFunction(js, &js_##TYPE##__count, "_count", 0)); \ JS_SetPropertyStr(js, globalThis, #TYPE "_proto", JS_DupValue(js,TYPE##_proto)); \ JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \ diff --git a/source/qjs_tracy.c b/source/qjs_tracy.c index cdd4132a..ceb03f02 100644 --- a/source/qjs_tracy.c +++ b/source/qjs_tracy.c @@ -3,9 +3,7 @@ #include #include #include "render.h" - -#include -#include +#include static JSValue js_tracy_fiber_enter(JSContext *js, JSValue self, int argc, JSValue *argv) { @@ -474,7 +472,11 @@ static JSValue js_tracy_gpu_collect(JSContext *js, JSValue self, int argc, JSVal static JSValue js_tracy_image(JSContext *js, JSValue self, int argc, JSValue *argv) { - return JS_UNDEFINED; +/* SDL_Surface *img = js2SDL_Surface(js,argv[0]); + SDL_Surface *scaled = SDL_ScaleSurface(img, 320,180,SDL_SCALEMODE_LINEAR); + ___tracy_emit_frame_image(scaled->pixels, scaled->w,scaled->h, 0,0); + SDL_DestroySurface(scaled); + return JS_UNDEFINED;*/ } #endif diff --git a/source/render.c b/source/render.c index 59a7b05b..f2406ebd 100644 --- a/source/render.c +++ b/source/render.c @@ -1,73 +1,7 @@ #include "render.h" -#include "sokol/sokol_gfx.h" -#include "sokol/sokol_glue.h" -#include "HandmadeMath.h" -#include - -sg_sampler std_sampler; -sg_sampler tex_sampler; - viewstate globalview = {0}; -#ifdef TRACY_ENABLE -#include - -#define DUMPSTAT(NAME) TracyCPlotI(#NAME, stats.NAME); - -void render_dump_trace() -{ - sg_frame_stats stats = sg_query_frame_stats(); - DUMPSTAT(num_passes) - DUMPSTAT(num_draw) - DUMPSTAT(num_tris) - DUMPSTAT(num_verts) - - DUMPSTAT(num_apply_pipeline) - DUMPSTAT(num_apply_bindings) - DUMPSTAT(num_apply_uniforms) - DUMPSTAT(size_apply_uniforms) - - - DUMPSTAT(size_update_buffer) - DUMPSTAT(size_append_buffer) - DUMPSTAT(size_update_image) - - DUMPSTAT(num_apply_viewport) - DUMPSTAT(num_apply_scissor_rect) -} - -#endif - -void render_trace_init(); - -void render_init() { - sg_setup(&(sg_desc){ - .environment = sglue_environment(), -// .logger = { .func = sg_logging }, - .buffer_pool_size = 1024, - .image_pool_size = 1024, - }); - -#ifdef TRACY_ENABLE - sg_enable_frame_stats(); - TracyCPlotConfig("size_apply_uniforms", TracyPlotFormatMemory, 1, 1, 5474985); - TracyCPlotConfig("size_update_buffer", TracyPlotFormatMemory, 1, 1, 547498235); - TracyCPlotConfig("size_append_buffer", TracyPlotFormatMemory, 1, 1, 12345615); - TracyCPlotConfig("size_update_image", TracyPlotFormatMemory, 1, 1, 49831049); -// render_trace_init(); -#endif - - std_sampler = sg_make_sampler(&(sg_sampler_desc){}); - tex_sampler = sg_make_sampler(&(sg_sampler_desc){ - .min_filter = SG_FILTER_LINEAR, - .mag_filter = SG_FILTER_LINEAR, - .mipmap_filter = SG_FILTER_LINEAR, - .wrap_u = SG_WRAP_REPEAT, - .wrap_v = SG_WRAP_REPEAT - }); -} - float *rgba2floats(float *r, struct rgba c) { r[0] = (float)c.r / RGBA_MAX; diff --git a/source/render.h b/source/render.h index 1feb50fb..117c90c2 100644 --- a/source/render.h +++ b/source/render.h @@ -1,18 +1,8 @@ #ifndef OPENGL_RENDER_H #define OPENGL_RENDER_H -#if defined __linux__ - #define SOKOL_GLCORE -#elif __EMSCRIPTEN__ - #define SOKOL_WGPU -#elif __WIN32 - #define SOKOL_D3D11 -#elif __APPLE__ - #define SOKOL_METAL -#endif - -#include "sokol/sokol_gfx.h" #include "HandmadeMath.h" +#include #define RGBA_MAX 255 @@ -21,9 +11,6 @@ extern struct rgba color_black; extern struct rgba color_clear; extern int TOPLEFT; -extern sg_sampler std_sampler; -extern sg_sampler tex_sampler; - typedef struct viewstate { HMM_Mat4 v; HMM_Mat4 p; @@ -56,8 +43,6 @@ struct rgba { unsigned char a; }; -void render_dump_trace(); - typedef struct rgba rgba; static inline rgba vec2rgba(HMM_Vec4 v) { @@ -68,7 +53,6 @@ static inline rgba vec2rgba(HMM_Vec4 v) { struct rect { float x,y,w,h; }; -typedef struct rect rect; float *rgba2floats(float *r, struct rgba c); diff --git a/source/render_trace.cpp b/source/render_trace.cpp index 4cfcca47..dee213aa 100644 --- a/source/render_trace.cpp +++ b/source/render_trace.cpp @@ -1,5 +1,4 @@ #include "glad.h" -#include "sokol/sokol_gfx.h" #include #include diff --git a/source/script.c b/source/script.c index 5710098c..5ab19689 100644 --- a/source/script.c +++ b/source/script.c @@ -1,7 +1,6 @@ #include "script.h" #include "jsffi.h" #include "stb_ds.h" -#include #include #include #include @@ -11,8 +10,6 @@ #include #include -#include - static JSContext *js = NULL; static JSRuntime *rt = NULL; diff --git a/source/texture.c b/source/texture.c index c9a106da..208d6da0 100644 --- a/source/texture.c +++ b/source/texture.c @@ -1,7 +1,6 @@ #include "texture.h" #include "render.h" -#include "sokol/sokol_gfx.h" #include #include #include @@ -21,97 +20,6 @@ struct rect ST_UNIT = {0.f, 0.f, 1.f, 1.f}; -static inline void write_pixel(unsigned char *data, int idx, rgba color) -{ - memcpy(data+idx, &color, sizeof(color)); -} - -static inline rgba get_pixel(unsigned char *data, int idx) -{ - rgba color; - memcpy(&color, data+idx, sizeof(color)); - return color; -} - -static inline unsigned char c_clamp(float value) { return (unsigned char) fmaxf(0.0f, fminf(255.0f, roundf(value))); } - -static inline rgba blend_colors(rgba a, rgba b) -{ - float a_a = a.a / 255.0f; - float b_a = b.a / 255.0f; - - float out_a = a_a + b_a * (1.0f - a_a); - rgba result; - - if (out_a == 0.0f) { - result.r = result.g = result.b = result.a = 0; - return result; - } - - // Use the c_clamp function to safely clamp the values within the range [0, 255] - result.r = c_clamp(((a.r * a_a) + (b.r * b_a * (1.0f - a_a))) / out_a); - result.g = c_clamp(((a.g * a_a) + (b.g * b_a * (1.0f - a_a))) / out_a); - result.b = c_clamp(((a.b * a_a) + (b.b * b_a * (1.0f - a_a))) / out_a); - result.a = c_clamp(out_a * 255.0f); - - return result; -} - -static inline rgba additive_blend(rgba a, rgba b) { - rgba result; - - result.r = c_clamp(a.r + b.r); - result.g = c_clamp(a.g + b.g); - result.b = c_clamp(a.b + b.b); - result.a = c_clamp((a.a + b.a) * 0.5f); // Blend alpha channels evenly - - return result; -} - -static inline rgba subtractive_blend(rgba a, rgba b) { - rgba result; - - result.r = c_clamp(a.r - b.r); - result.g = c_clamp(a.g - b.g); - result.b = c_clamp(a.b - b.b); - result.a = c_clamp((a.a + b.a) * 0.5f); // Blend alpha channels evenly - - return result; -} - -static inline rgba multiplicative_blend(rgba a, rgba b) { - rgba result; - - result.r = c_clamp((a.r * b.r) / 255.0f); - result.g = c_clamp((a.g * b.g) / 255.0f); - result.b = c_clamp((a.b * b.b) / 255.0f); - result.a = c_clamp((a.a + b.a) * 0.5f); // Blend alpha channels evenly - - return result; -} - -static inline rgba dodge_blend(rgba a, rgba b) { - rgba result; - - result.r = c_clamp(a.r == 255 ? 255 : (b.r * 255) / (255 - a.r)); - result.g = c_clamp(a.g == 255 ? 255 : (b.g * 255) / (255 - a.g)); - result.b = c_clamp(a.b == 255 ? 255 : (b.b * 255) / (255 - a.b)); - result.a = c_clamp((a.a + b.a) * 0.5f); // Blend alpha channels evenly - - return result; -} - -static inline rgba burn_blend(rgba a, rgba b) { - rgba result; - - result.r = c_clamp(a.r == 0 ? 0 : 255 - ((255 - b.r) * 255) / a.r); - result.g = c_clamp(a.g == 0 ? 0 : 255 - ((255 - b.g) * 255) / a.g); - result.b = c_clamp(a.b == 0 ? 0 : 255 - ((255 - b.b) * 255) / a.b); - result.a = c_clamp((a.a + b.a) * 0.5f); // Blend alpha channels evenly - - return result; -} - unsigned int next_pow2(unsigned int v) { v--; @@ -196,36 +104,6 @@ struct texture *texture_fromdata(void *raw, long size) return tex; } -static double fade (double t) { return t*t*t*(t*(t*6-15)+10); } -double grad (int hash, double x, double y, double z) -{ - int h = hash&15; - double u = h<8 ? x : y; - double v = h<4 ? y : h==12||h==14 ? x : z; - return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); -/* alt */ -/* switch(hash & 0xF) - { - case 0x0: return x + y; - case 0x1: return -x + y; - case 0x2: return x - y; - case 0x3: return -x - y; - case 0x4: return x + z; - case 0x5: return -x + z; - case 0x6: return x - z; - case 0x7: return -x - z; - case 0x8: return y + z; - case 0x9: return -y + z; - case 0xA: return y - z; - case 0xB: return -y - z; - case 0xC: return y + x; - case 0xD: return -y + z; - case 0xE: return y - x; - case 0xF: return -y - z; - default: return 0; // never happens - }*/ -} - void texture_save(texture *tex, const char *file) { if (!tex->data) return; @@ -248,74 +126,6 @@ void texture_save(texture *tex, const char *file) }); } -// copy texture src to dest -// sx and sy are the destination coordinates to copy to -// sw the width of the destination to take in pixels -// sh the height of the destination to take in pixels -int texture_blit(texture *dst, texture *src, rect dstrect, rect srcrect, int tile) { - if (!src || !dst || !src->data || !dst->data) return 0; - - float scaleX = srcrect.w / dstrect.w; - float scaleY = srcrect.h / dstrect.h; - - if (srcrect.x < 0 || srcrect.y < 0 || srcrect.x + srcrect.w > src->width || - dstrect.x < 0 || dstrect.y < 0 || dstrect.x + dstrect.w > dst->width || - srcrect.y + srcrect.h > src->height || dstrect.y + dstrect.h > dst->height) { - return false; // Rectangles exceed texture bounds - } - - for (int dstY = 0; dstY < dstrect.h; ++dstY) { - for (int dstX = 0; dstX < dstrect.w; ++dstX) { - int srcX; - int srcY; - - if (tile) { - srcX = srcrect.x + (dstX % (int)srcrect.w); - srcY = srcrect.y + (dstY % (int)srcrect.h); - } else { - srcX = srcrect.x + (int)(dstX * scaleX); - srcY = srcrect.y + (int)(dstY * scaleY); - } - - int srcIndex = (srcY * src->width + srcX) * 4; - int dstIndex = ((dstrect.y + dstY) * dst->width + (dstrect.x + dstX)) * 4; - - rgba srccolor = get_pixel(src->data, srcIndex); - rgba dstcolor = get_pixel(dst->data, dstIndex); - rgba color = blend_colors(srccolor, dstcolor); - write_pixel(dst->data, dstIndex, color); - } - } - - return 1; -} - -int texture_fill_rect(texture *tex, struct rect rect, struct rgba color) -{ - if (!tex || !tex->data) return 0; - - int x_end = rect.x+rect.w; - int y_end = rect.y+rect.h; - - if (rect.x < 0 || rect.y < 0 || x_end > tex->width || y_end > tex->height) return 0; - - for (int j = rect.y; j < y_end; ++j) - for (int i = rect.x; i < x_end; ++i) { - int index = (j*tex->width+i)*4; - write_pixel(tex->data, index, color); - } - - return 1; -} - -void swap_pixels(unsigned char *p1, unsigned char *p2) { - for (int i = 0; i < 4; ++i) { - unsigned char tmp = p1[i]; - p1[i] = p2[i]; - p2[i] = tmp; - } -} - texture *texture_scale(texture *tex, int width, int height) { texture *new = calloc(1, sizeof(*new)); @@ -327,125 +137,7 @@ texture *texture_scale(texture *tex, int width, int height) return new; } -int texture_flip(texture *tex, int y) -{ - if (!tex || !tex->data) return -1; - - int width = tex->width; - int height = tex->height; - - if (y) { - for (int row = 0; row < height / 2; ++row) { - for (int col = 0; col < width; ++col) { - unsigned char *top = tex->data+((row*width+col)*4); - unsigned char *bottom = tex->data+(((height-row-1)*width+col)*4); - swap_pixels(top,bottom); - } - } - } else { - for (int row = 0; row < height; ++row) { - for (int col = 0; col < width / 2; ++col) { - unsigned char *left = tex->data+((row*width+col)*4); - unsigned char *right = tex->data+((row*width+(width-col-1))*4); - swap_pixels(left,right); - } - } - } - - return 0; -} - - -int texture_write_pixel(texture *tex, int x, int y, rgba color) -{ - if (x < 0 || x >= tex->width || y < 0 || y >= tex->height) return 0; - int i = (y * tex->width + x) * 4; - write_pixel(tex->data, i, color); - - return 1; -} - -texture *texture_dup(texture *tex) -{ - texture *new = calloc(1, sizeof(*new)); - *new = *tex; - new->data = malloc(new->width*new->height*4); - memcpy(new->data, tex->data, new->width*new->height*4*sizeof(new->data)); - - return new; -} - -sg_image_data tex_img_data(texture *tex, int mipmaps) -{ - if (!mipmaps) { - sg_image_data sg_img_data = {0}; - sg_img_data.subimage[0][0] = (sg_range) {.ptr = tex->data, .size = tex->width*tex->height*4}; - return sg_img_data; - } - - sg_image_data sg_img_data = {0}; - - int mips = mip_levels(tex->width, tex->height)+1; - - int mipw, miph; - mipw = tex->width; - miph = tex->height; - - sg_img_data.subimage[0][0] = (sg_range){ .ptr = tex->data, .size = mipw*miph*4 }; - - unsigned char *mipdata[mips]; - mipdata[0] = tex->data; - - for (int i = 1; i < mips; i++) { - int w, h, mipw, miph; - mip_wh(tex->width, tex->height, &mipw, &miph, i-1); // mipw miph are previous iteration - mip_wh(tex->width, tex->height, &w, &h, i); - mipdata[i] = malloc(w * h * 4); - stbir_resize_uint8_linear(mipdata[i-1], mipw, miph, 0, mipdata[i], w, h, 0, 4); - sg_img_data.subimage[0][i] = (sg_range){ .ptr = mipdata[i], .size = w*h*4 }; - tex->vram += w*h*4; - - mipw = w; - miph = h; - } -} - -int texture_fill(texture *tex, struct rgba color) -{ - if (!tex || !tex->data) return 0; // Ensure valid texture and pixel data - - // Loop through every pixel in the texture - for (int y = 0; y < tex->height; ++y) { - for (int x = 0; x < tex->width; ++x) { - int index = (y * tex->width + x) * 4; - write_pixel(tex->data, index, color); - } - } - - return 1; -} - -void texture_load_gpu(texture *tex) -{ - if (!tex->data) return; - if (tex->id.id == 0) { - // Doesn't exist, so make a new one - sg_image_data img_data = tex_img_data(tex, 0); - tex->id = sg_make_image(&(sg_image_desc){ - .type = SG_IMAGETYPE_2D, - .width = tex->width, - .height = tex->height, - .usage = SG_USAGE_DYNAMIC, - .num_mipmaps = 1 - }); - sg_update_image(tex->id, &img_data); - } else { - sg_image_data img_data = tex_img_data(tex,0); - sg_update_image(tex->id, &img_data); - } -} - -sapp_icon_desc texture2icon(texture *tex) +/*sapp_icon_desc texture2icon(texture *tex) { sapp_icon_desc desc = {0}; if (!tex->data) return desc; @@ -476,3 +168,4 @@ sapp_icon_desc texture2icon(texture *tex) return desc; } +*/ diff --git a/source/texture.h b/source/texture.h index 803a8bab..c3417b08 100644 --- a/source/texture.h +++ b/source/texture.h @@ -1,15 +1,11 @@ #ifndef TEXTURE_H #define TEXTURE_H -#include "sokol/sokol_gfx.h" #include "HandmadeMath.h" #include "render.h" #include - #include "stb_rect_pack.h" - -#include "sokol_app.h" -#include "sokol/util/sokol_imgui.h" +#include #define TEX_SPEC 0 #define TEX_NORM 1 @@ -24,7 +20,8 @@ extern struct rect ST_UNIT; /* Represents an actual texture on the GPU */ struct texture { - sg_image id; /* ID reference for the GPU memory location of the texture */ + SDL_Texture *id; + SDL_Surface *surface; int width; int height; HMM_Vec3 dimensions; @@ -50,15 +47,6 @@ texture *texture_scale(texture *tex, int width, int height); // dup and scale th void texture_free(JSRuntime *rt,texture *tex); void texture_offload(texture *tex); // Remove the data from this texture -void texture_load_gpu(texture *tex); // Upload this data to the GPU if it isn't already there. Replace it if it is. - -int texture_write_pixel(texture *tex, int x, int y, struct rgba color); -int texture_fill(texture *tex, struct rgba color); -int texture_fill_rect(texture *tex, struct rect rect, struct rgba color); -int texture_blit(texture *dst, texture *src, struct rect dstrect, struct rect srcrect, int tile); // copies src into dst, using their respective squares, scaling if necessary -int texture_flip(texture *tex, int y); - -sapp_icon_desc texture2icon(texture *tex); void texture_save(texture *tex, const char *file); // save the texture data to the given file diff --git a/source/thirdparty/sokol/.editorconfig b/source/thirdparty/sokol/.editorconfig deleted file mode 100644 index 2e854498..00000000 --- a/source/thirdparty/sokol/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -root=true -[**] -indent_style=space -indent_size=4 -trim_trailing_whitespace=true -insert_final_newline=true - -[*.yml] -indent_size=2 diff --git a/source/thirdparty/sokol/.github/workflows/gen_bindings.yml b/source/thirdparty/sokol/.github/workflows/gen_bindings.yml deleted file mode 100644 index c1b52b7e..00000000 --- a/source/thirdparty/sokol/.github/workflows/gen_bindings.yml +++ /dev/null @@ -1,331 +0,0 @@ -name: Bindings - -on: [push, pull_request] - -jobs: - test-windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - name: test_win - run: | - cd tests - test_win.cmd - shell: cmd - - test-mac: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - uses: seanmiddleditch/gha-setup-ninja@master - - name: test_macos - run: | - cd tests - ./test_macos.sh - - test-linux: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: seanmiddleditch/gha-setup-ninja@master - - name: prepare - run: | - sudo apt-get update - sudo apt-get install libgl1-mesa-dev libegl1-mesa-dev mesa-common-dev xorg-dev libasound-dev - - name: test_linux - run: | - cd tests - ./test_linux.sh - - gen-bindings: - needs: [ test-windows, test-mac, test-linux ] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-zig - path: bindgen/sokol-zig - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-nim - path: bindgen/sokol-nim - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-odin - path: bindgen/sokol-odin - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-rust - path: bindgen/sokol-rust - - name: generate - run: | - cd bindgen - python3 gen_all.py - - name: upload-zig-artifact - uses: actions/upload-artifact@v4 - with: - name: ignore-me-zig - retention-days: 1 - path: bindgen/sokol-zig/src/sokol - - name: upload-nim-artifact - uses: actions/upload-artifact@v4 - with: - name: ignore-me-nim - retention-days: 1 - path: bindgen/sokol-nim/src/sokol - - name: upload-odin-artifact - uses: actions/upload-artifact@v4 - with: - name: ignore-me-odin - retention-days: 1 - path: | - bindgen/sokol-odin/sokol - bindgen/sokol-odin/c - - name: upload-rust-artifact - uses: actions/upload-artifact@v4 - with: - name: ignore-me-rust - retention-days: 1 - path: bindgen/sokol-rust/src - - test-zig: - needs: gen-bindings - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{matrix.os}} - steps: - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-zig - - uses: goto-bus-stop/setup-zig@v2 - - uses: actions/download-artifact@v4 - with: - name: ignore-me-zig - path: src/sokol - - name: prepare - if: runner.os == 'Linux' - run: | - sudo apt-get update - sudo apt-get install libgl1-mesa-dev libegl1-mesa-dev mesa-common-dev xorg-dev libasound-dev - - name: build - run: zig build - - test-nim: - needs: gen-bindings - strategy: - fail-fast: false - matrix: - #os: [ubuntu-latest, macos-latest, windows-latest] - os: [ubuntu-latest, macos-latest ] - runs-on: ${{matrix.os}} - steps: - - uses: jiro4989/setup-nim-action@v1 - with: - nim-version: '2.x' - repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-nim - - uses: actions/download-artifact@v4 - with: - name: ignore-me-nim - path: src/sokol - - if: runner.os == 'Linux' - name: prepare - run: | - sudo apt-get update - sudo apt-get install libgl1-mesa-dev libegl1-mesa-dev mesa-common-dev xorg-dev libasound-dev - - name: build - run: | - nimble install -Y - nimble install glm -Y - nimble build_all - - test-odin: - needs: gen-bindings - strategy: - fail-fast: false - matrix: - # FIXME: macOS Odin vs Homebrew LLVM currently seems broken - # os: [ubuntu-latest, macos-latest, windows-latest] - os: [ubuntu-latest, windows-latest] - runs-on: ${{matrix.os}} - steps: - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-odin - - uses: actions/download-artifact@v4 - with: - name: ignore-me-odin - # NOTE: see https://github.com/floooh/sokol-odin/blob/main/.github/workflows/main.yml - - uses: ilammy/msvc-dev-cmd@v1 - - if: runner.os == 'Linux' - name: prepare-linux - run: | - sudo apt-get update - sudo apt-get install libglu1-mesa-dev mesa-common-dev xorg-dev libasound-dev llvm-14 - curl -L https://github.com/odin-lang/Odin/releases/download/dev-2023-08/odin-ubuntu-amd64-dev-2023-08.zip --output odin.zip - unzip odin.zip - chmod a+x ./odin - ./build_clibs_linux.sh - - if: runner.os == 'macOS' - name: prepare-macos - run: | - brew install llvm@14 - curl -L https://github.com/odin-lang/Odin/releases/download/dev-2023-08/odin-macos-amd64-dev-2023-08.zip --output odin.zip - unzip odin.zip - chmod a+x ./odin - ./build_clibs_macos.sh - - if: runner.os == 'Windows' - name: prepare-windows - shell: cmd - run: | - curl -L https://github.com/odin-lang/Odin/releases/download/dev-2023-08/odin-windows-amd64-dev-2023-08.zip --output odin.zip - unzip odin.zip - build_clibs_windows.cmd - - name: build - run: | - ./odin build examples/clear -debug - ./odin build examples/triangle -debug - ./odin build examples/quad -debug - ./odin build examples/bufferoffsets -debug - ./odin build examples/cube -debug - ./odin build examples/noninterleaved -debug - ./odin build examples/texcube -debug - ./odin build examples/shapes -debug - ./odin build examples/offscreen -debug - ./odin build examples/instancing -debug - ./odin build examples/mrt -debug - ./odin build examples/blend -debug - ./odin build examples/debugtext -debug - ./odin build examples/debugtext-print -debug - ./odin build examples/debugtext-userfont -debug - ./odin build examples/saudio -debug - ./odin build examples/sgl -debug - ./odin build examples/sgl-points -debug - ./odin build examples/sgl-context -debug - - test-rust: - needs: gen-bindings - env: - CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse - strategy: - fail-fast: false - matrix: - # os: [ubuntu-latest, macos-latest, windows-latest] - os: [ubuntu-latest, windows-latest] - runs-on: ${{matrix.os}} - steps: - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-rust - - uses: actions/download-artifact@v4 - with: - name: ignore-me-rust - path: src - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - - name: prepare-linux - if: runner.os == 'Linux' - run: | - sudo apt-get update - sudo apt-get install libglu1-mesa-dev mesa-common-dev xorg-dev libasound-dev - - name: build - run: | - cargo --version - cargo build --examples --verbose - - # only deploy the bindings for commits on the main branch - deploy-zig: - needs: test-zig - if: github.ref == 'refs/heads/master' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-zig - ssh-key: ${{ secrets.GHACTIONS_ZIG_PUSH }} - - uses: actions/download-artifact@v4 - with: - name: ignore-me-zig - path: src/sokol - - name: "commit and push" - run: | - git config user.email "none" - git config user.name "GH Action" - git add -A - git diff-index --quiet HEAD || git commit -m "updated (https://github.com/floooh/sokol/commit/${{ github.sha }})" - git push - - deploy-nim: - needs: test-nim - if: github.ref == 'refs/heads/master' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-nim - ssh-key: ${{ secrets.GHACTIONS_NIM_PUSH }} - - uses: actions/download-artifact@v4 - with: - name: ignore-me-nim - path: src/sokol - - name: "commit and push" - run: | - git config user.email "none" - git config user.name "GH Action" - git add -A - git diff-index --quiet HEAD || git commit -m "updated (https://github.com/floooh/sokol/commit/${{ github.sha }})" - git push - - deploy-odin: - needs: test-odin - if: github.ref == 'refs/heads/master' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-odin - ssh-key: ${{ secrets.GHACTIONS_ODIN_PUSH }} - - uses: actions/download-artifact@v4 - with: - name: ignore-me-odin - - name: "commit and push" - run: | - git config user.email "none" - git config user.name "GH Action" - git add -A - git diff-index --quiet HEAD || git commit -m "updated (https://github.com/floooh/sokol/commit/${{ github.sha }})" - git push - - deploy-rust: - needs: test-rust - env: - CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse - if: github.ref == 'refs/heads/master' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - repository: floooh/sokol-rust - ssh-key: ${{ secrets.GHACTIONS_RUST_PUSH }} - - uses: actions/download-artifact@v4 - with: - name: ignore-me-rust - path: src - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - - name: "cargo fmt" - run: cargo fmt - - name: "commit and push" - run: | - git config user.email "none" - git config user.name "GH Action" - git status -vv - git add -A - git diff-index --quiet HEAD || git commit -m "updated (https://github.com/floooh/sokol/commit/${{ github.sha }})" - git push diff --git a/source/thirdparty/sokol/.github/workflows/main.yml b/source/thirdparty/sokol/.github/workflows/main.yml deleted file mode 100644 index 4d7ddf39..00000000 --- a/source/thirdparty/sokol/.github/workflows/main.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: "Build & Test" - -on: [push, pull_request] - -jobs: - windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - name: test_win - run: | - cd tests - test_win.cmd - shell: cmd - mac: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - uses: seanmiddleditch/gha-setup-ninja@master - - name: test_macos - run: | - cd tests - ./test_macos.sh - ios: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: test_ios - run: | - cd tests - ./test_ios.sh - linux: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: seanmiddleditch/gha-setup-ninja@master - - name: prepare - run: | - sudo apt-get update - sudo apt-get install libgl1-mesa-dev libegl1-mesa-dev mesa-common-dev xorg-dev libasound-dev - - name: test_linux - run: | - cd tests - ./test_linux.sh - emscripten: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: seanmiddleditch/gha-setup-ninja@master - - name: test_emscripten - run: | - cd tests - ./test_emscripten.sh - android: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: seanmiddleditch/gha-setup-ninja@master - - uses: actions/setup-java@v1 - with: - java-version: '8' - - name: test_android - run: | - cd tests - ./test_android.sh diff --git a/source/thirdparty/sokol/.gitignore b/source/thirdparty/sokol/.gitignore deleted file mode 100644 index 58627d69..00000000 --- a/source/thirdparty/sokol/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.vscode/ -build/ -#>fips -# this area is managed by fips, do not edit -.fips-* -*.pyc -# NOTE: if you use sokol_gfx.h and sokol_app.h together, make sure to update both. This is -because the pixel format enum in sokol_gfx.h has been shuffled around a bit, and as a result, some internal -pixel format constants in sokol_app.h had to move too! - -- sokol_gfx.h: some minor new features (non-breaking): - - the struct `sg_pixel_format` has two new items: - - `bool compressed`: true if this is a hardware-compressed pixel format - - `int bytes_per_pixel`: as the name says, with the caveat that this is - zero for compressed pixel formats (because the smallest element in compressed formats is a block, not a pixel) - - two previously private helper functions have been exposed to help with size computations - for texture data, these may be useful when preparing image data for consumption by `sg_make_image()` - and `sg_update_image()`: - - `int sg_query_row_pitch(sg_pixel_format fmt, int width, int row_align_bytes)`: - Computes the number of bytes in a texture row for a given pixel format. A 'row' has - different meanings for uncompressed vs compressed formats: For uncompressed pixel - formats, a row is a single line of pixels, while for compressed formats, a row is - a line of 'compression blocks'. `width` is always in pixels. - - `int sg_query_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align_bytes)`: - Computes number of bytes in a texture surface (e.g. a single mipmap) for a given - pixel format. `width` and `height` are always in pixels. - - The `row_align_bytes` parameter is for added flexibility. For image data that goes into - the `sg_make_image()` or `sg_update_image()` functions this should generally be 1, because these - functions take tightly packed image data as input no matter what alignment restrictions - exist in the backend 3D APIs. -- Related issue: https://github.com/floooh/sokol/issues/946, and PR: https://github.com/floooh/sokol/pull/962 - -#### 03-Jan-2024 - -- sokol_nuklear.h: `snk_handle_event()` now returns a bool to indicate whether the - event was handled by Nuklear (this allows an application to skip its own event - handling if Nuklear already handled the event). Issue link: https://github.com/floooh/sokol/issues/958, - fixed in PR: https://github.com/floooh/sokol/pull/959. Many thanks to @adamrt for the PR! - -#### 02-Jan-2024 - -Happy New Year! A couple of input-related changes in the sokol_app.h Emscripten backend: - -- Mouse and touch events now bubble up to the HTML document instead of being consumed, in some scenarios this - allows better integration with the surrounding web page. To prevent event bubbling, - call `sapp_consume_event()` from within the sokol_app.h event callback function. -- **NOTE**: wheel/scroll events behave as before and are always consumed. This prevents - an ugly "scroll bumping" effect when a wheel event bubbles up on a page where - scrolling shouldn't be possible. -- The hidden HTML text input field hack for text input on mobile browsers has been - removed. This idea never really worked across all browsers, and it actually - interfered with Dear ImGui text input fields because the hidden HTML text field - generated focus-in/out events which confused the Dear ImGui input handling code. - -Those changes fix a couple of problem when trying to integrate sokol_app.h applications -into VSCode webview panels, see: https://marketplace.visualstudio.com/items?itemName=floooh.vscode-kcide - -Related PR: https://github.com/floooh/sokol/pull/939 - -#### 10-Nov-2023 - -A small change in the sokol_gfx.h GL backend on Windows only: - -PR https://github.com/floooh/sokol/pull/839 has been merged, in debug mode this creates -the GL context with WGL_CONTEXT_DEBUG_BIT_ARB. Thanks to @castano for the PR! - -#### 06-Nov-2023 - -A bugfix in the sokol_gfx.h D3D11 backend, and some related cleanup when creating depth-stencil -render target images and resource views: - -- fixed: render target images with format SG_PIXELFORMAT_DEPTH_STENCIL triggered a validation - error because the pixel format capabilities code marked them as non-renderable. Now - the SG_PIXELFORMAT_DEPTH_STENCIL pixel format is properly reported as renderable. -- the DXGIFormats for SG_PIXELFORMAT_DEPTH_STENCIL images are now as follows: - - D3D11 texture object: DXGI_FORMAT_R24G8_TYPELESS - - D3D11 shader-resource-view object: DXGI_FORMAT_R24_UNORM_X8_TYPELESS - - D3D11 depth-stencil-view object: DXGI_FORMAT_D24_UNORM_S8_UINT - -Related PR: https://github.com/floooh/sokol/pull/937 - -#### 30-Oct-2023 - -Some sokol_gfx.h backend-specific updates and tweaks (very minor chance that this is breaking if you are injecting textures into the D3D11 backend). - -- a new set of public API functions to access the native backend 3D-API resource objects of - sokol-gfx resource objects: - - ``` - sg_[api]_[type]_info sg_[api]_query_[type]_info(sg_[type]) - ``` - ...where `[api]` is any of `[gl, d3d11, mtl, wgpu]` and `[type]` is any of `[buffer, image, sampler, shader, pipeline, pass]`. - - This is mainly useful when mixing native 3D-API code with sokol-gfx code. - - See issue https://github.com/floooh/sokol/issues/931 for details. - -- WebGPU backend: `sg_make_image()` will no longer automatically create a WebGPU texture-view object when injecting a WebGPU texture object, instead -this must now be explicitly provided. - -- D3D11 backend: `sg_make_image()` will no longer automatically create a -shader-resource-view object when injecting a D3D11 texture object, and -vice versa, a texture object will no longer be looked up from an injected -shader-resource-view object (e.g. the injection rules are now more straightforward and explicit). See issue https://github.com/floooh/sokol/issues/930 for details. - -For the detailed changes, see PR https://github.com/floooh/sokol/pull/932. - -#### 27-Oct-2023 - -Fix broken render-to-mipmap in the sokol_gfx.h GL backend. - -There was a subtle bug / "feature gap" lurking in sokol_gfx.h GL backend: trying -to render to any mipmap except the top-level mipmap resulted in a black screen -because of an incomplete-framebuffer error. This is fixed now. The changes in detail: - -- creating a texture in the GL backend now sets the GL_TEXTURE_MAX_LEVEL property - (this is the fix to make everything work) -- the framebuffer completeness check in the GL backend now has more detailed error logging -- in the validation layer, the requirement that a sampler that's used with a - single-mipmap-texture must use `.mipmap_filter = SG_FILTER_NONE` has been - relaxed (a later update will remove SG_FILTER_NONE entirely since it's not needed anymore - and the concept of a "none" mipmap filter only exists in GL and Metal, but not D3D, WebGPU - and Vulkan) - -Ticket: https://github.com/floooh/sokol/issues/923 - -PR: https://github.com/floooh/sokol/pull/924 - -There's also a new render-to-mipmap sample which covers to close this 'feature gap': - -https://floooh.github.io/sokol-html5/miprender-sapp.html - -A couple of similar samples will follow over the next few days -(rendering to texture array layers and 3d texture slices). - -#### 26-Oct-2023 - -- sokol_app.h gl: fix a regression introduced in https://github.com/floooh/sokol/pull/916 - which could select the wrong framebuffer pixel format and break rendering - on some GL drivers (in my case: an older Intel GPU). - - If you are using the GL backend on Windows, please make sure to upgrade! - -#### 23-Oct-2023 - -- sokol_app.h gl: some further startup optimizations in the WGL code path - via PR https://github.com/floooh/sokol/pull/916 - -#### 21-Oct-2023 - -The major topic of this update is the 'finalized' WebGPU support in sokol_gfx.h and sokol_app.h. - -- WebGPU samples are hosted here: - - https://floooh.github.io/sokol-webgpu/ - -- WebGL2 samples remain hosted here: - - https://floooh.github.io/sokol-html5/ - -- Please read the following blog post as introduction: - - https://floooh.github.io/2023/10/16/sokol-webgpu.html - -- ...and the changelog and updated documentation in the sokol-shdc repository: - - https://github.com/floooh/sokol-tools - -- You'll also need to update the sokol-shdc binaries: - - https://github.com/floooh/sokol-tools-bin - -- Please also read the following new or updated sections in the embedded sokol_gfx.h header documentation: - - - `ON SHADER CREATION` - - `ON SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT AND SG_SAMPLERTYPE_NONFILTERING` - - `WEBGPU CAVEATS` - - Please do this especially when using any of the following texture pixel formats, as you will most likely encounter new validation layer errors: - - - `SG_PIXELFORMAT_R32F` - - `SG_PIXELFORMAT_RG32F` - - `SG_PIXELFORMAT_RGBA32F` - -- There is a tiny breaking change in the sokol_gfx.h API (only requires action when not using sokol-shdc): - - - the following `sg_sampler_type` enum items have been renamed to better match their WebGPU counterparts: - - SG_SAMPLERTYPE_SAMPLE => SG_SAMPLERTYPE_FILTERING - - SG_SAMPLERTYPE_COMPARE => SG_SAMPLERTYPE_COMPARISON - - - the enum `sg_image_sample_type` gained a new item: - - SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT - - - the enum `sg_sampler_type` gained a new item: - - SG_SAMPLERTYPE_NONFILTERING - -- The sokol_gfx.h struct `sg_desc` has two new items: - - `.wgpu_bindgroups_cache_size` - must be power-of-2, default: 1024 - - `.wgpu_disable_bindgroups_cache` - default: false - -- sokol_gfx.h gained the following new public API functions to query per-frame information: - - `sg_frame_stats sg_query_frame_stats()` - - `void sg_enable_frame_stats(void)` - - `void sg_disable_frame_stats(void)` - - `bool sg_frame_stats_enabled(void)` - - Frame statistics gathering is enabled after startup, but can be temporarily - disabled and enabled again via `sg_disable_frame_stats()` and `sg_enable_frame_stats`. - -- The sokol_gfx.h validation layer has new validation checks in `sg_make_shader()` - regarding image/sampler pair compatibility (WebGPU is particularly strict about - this stuff). - -- In sokol_app.h, the old wip WebGPU device and swapchain setup code is now implemented - in pure C code (previously this was a mix of Javascript and C). - -- Also note that sokol_app.h currently only supports WebGPU in the Emscripten backend. - If you want to use sokol_gfx.h with the WebGPU backend in a native scenario, you'll have - to use a different window system glue library (like GLFW). The sokol-samples directory - has a handful of examples for using sokol_gfx.h + Dawn + GLFW. - -- The following headers have been made compatible with the sokol_gfx.h WebGPU backend - (mainly by embedding WGSL shader code): - - sokol_debugtext.h - - sokol_fontstash.h - - sokol_gl.h - - sokol_spine.h - - sokol_imgui.h (also required some more changes for embedding `unfilterable-float` - textures, since these now require separate shader and pipeline objects) - - sokol_nuklear.h (works in WebGPU, but doesn't contain the work from sokol_imgui.h - to support `unfilterable-float` user textures) - -- sokol_gfx_imgui.h gained a new function `sg_imgui_draw_menu()` which renders a - menu panel to show/hide all debug windows. Previously this had to be done - outside the header. - -- sokol_gfx_imgui.h gained a new 'frame stats' window, which allows to peak into - sokol_gfx.h frame-rendering internals. This basically visualizes the struct - `sg_frame_stats` returned by the new sokol_gfx.h function `sg_query_frame_stats()`. - -- The sokol-samples repository gained 3 new samples: - - cubemap-jpeg-sapp.c (load a cubemap from separate JPEG files) - - cubemaprt-sapp.c (render into cubemap faces - this demo actually existed a while but wasn't "official" so far) - - drawcallperf-sapp.c (a sample to explore the performance overhead of sg_apply_bindings, sg_apply_uniforms and sg_draw) - -#### 03-Oct-2023 - -- sokol_app.h win/gl: PR https://github.com/floooh/sokol/pull/886 has been merged, this makes - GL context initialization on Windows slightly more efficient. Many thanks to @dtrebilco! - -#### 25-Sep-2023 - -- The allocator callback functions in all headers that support custom allocators have been renamed - from `alloc` and `free` to `alloc_fn` and `free_fn`, this is because the symbol `free` is quite - likely to collide with a preprocessor macro of the same name if the standard C allocator is - replaced with a custom allocator. - - This is a breaking change only if you've been providing your own allocator functions to - the sokol headers. - - See issue https://github.com/floooh/sokol/issues/903 and PR https://github.com/floooh/sokol/pull/908 - for details. - -#### 23-Sep-2023 - -- sokol_gfx.h gl: Allow to inject an external GL framebuffer id into the sokol-gfx default - pass. See PR https://github.com/floooh/sokol/pull/899 and issue https://github.com/floooh/sokol/issues/892 - for details. Many thanks to @danielchasehooper for the discussion and PR! - - Further down the road I want to make the whole topic more flexible while at the same time - simplifying the sokol-gfx API, see here: https://github.com/floooh/sokol/issues/904 - -#### 22-Sep-2023 - -- sokol_gfx.h: Fixed a Metal validation error on Intel Macs when creating textures (Intel Macs - have unified memory, but don't support textures in shared storage mode). This was a regression - in the image/sampler split update in mid-July 2023. Fixes issue https://github.com/floooh/sokol/issues/905 - via PR https://github.com/floooh/sokol/pull/907. - -#### 19-Sep-2023 - -- sokol_fetch.h: fixed a minor issue where a request that was cancelled before it was dispatched - had an incomplete response state set in the response callback (the `finished`, `failed` and - `error_code` fields were not set). This fixes issue https://github.com/floooh/sokol/issues/882 - via PR https://github.com/floooh/sokol/pull/898 - -#### 18-Sep-2023 - -- PR https://github.com/floooh/sokol/pull/893 has been merged, this fixes a minor issue - in the GL backend when using an injected texture as framebuffer attachment. -- Issue https://github.com/floooh/sokol/issues/884 has been fixed via PR https://github.com/floooh/sokol/pull/894, - this adds missing error code paths in the Metal backend when Metal object creation fails. -- Clarified `sapp_run()` behaviour in the sokol_app.h documentation header (search for `OPTIONAL: DON'T HIJACK main()`) -- sokol_args.h now fully supports "key-only args", see issue https://github.com/floooh/sokol/issues/876 for details, - fixed via PR https://github.com/floooh/sokol/pull/896 - -#### 17-Sep-2023 - -- The sokol-gfx Metal backend now adds debug labels to Metal resource objects and - also passes through the `sg_push/pop_debug_group()` calls. If you use the push/pop - debug group calls, please be aware of the following limitations: - - - a push inside a render pass must have an associated pop inside the same render pass - - a push outside any render pass must have an associated pop outside any render pass - - Metal will ignore any push/pop calls outside render passes (this is because in Metal - these are MTLCommandEncoder methods) - - Associated issue: https://github.com/floooh/sokol/issues/889, and PR: https://github.com/floooh/sokol/pull/890. - -#### 09-Sep-2023 - -- a small PR has been merged which fixes a redundant glBindFramebuffer() in the GLES3 backend - in `sg_end_pass()` (see: https://github.com/floooh/sokol/pull/878), many thanks to @danielchasehooper - for catching that issue! -- sokol_imgui.h has been fixed for cimgui 1.89.9 (see https://github.com/floooh/sokol/issues/879) - -#### 28-Aug-2023 - -**sokol_gfx.h metal**: A new attempt at fixing a rare Metal validation layer -error about MTKView swapchain resource lifetimes. See PR https://github.com/floooh/sokol/pull/873 -for details. - -#### 26-Jul-2023 - -**sokol_nuklear.h**: The same image+sampler support has been added as in sokol_imgui.h -three days ago: - -- a new object type `snk_image_t` which wraps a sokol-gfx image and sampler - under a common handle -- new functions: - - snk_make_image() - - snk_destroy_image() - - snk_query_image_desc() - - snk_image_from_nkhandle() -- the function snk_nkhandle() now takes an snk_image_t handle instead of an sg_image handle -- the nuklear.h header needs to be included before the declaration (not just the implementation), - this was already required before, but now you get a proper error message if the include is missing -- the 'standard' logging- and error-reporting callback has been added as in the other sokol headers - (don't forget to add a logging callback in snk_setup(), otherwise sokol-nuklear will be silent) -- since sokol-nuklear now needs to allocate memory, an allocator can now be provided to the - snk_setup() call (otherwise malloc/free will be used) - -Please also read the new documentation section `ON USER-PROVIDED IMAGES AND SAMPLERS` -in sokol_nuklear.h, and also check out the (rewritten) sample: - -https://floooh.github.io/sokol-html5/nuklear-images-sapp.html - -Associated PR: https://github.com/floooh/sokol/pull/862 - -#### 23-Jul-2023 - -**sokol_imgui.h**: Add proper support for injecting user-provided sokol-gfx -images and samplers into Dear ImGui UIs. With the introduction of separate -sampler objects in sokol_gfx.h there's a temporary feature regression in -sokol_imgui.h and sokol_nuklear.h in that user provided images had to use a -shared sampler that's hardwired into the respective headers. This update fixes -this problem for sokol_imgui.h, with a similar fix for sokol_nuklear.h coming -up next. - -The sokol_imgui.h changes in detail are: - -- a new object type `simgui_image_t` which wraps a sokol-gfx image and sampler - object under a common handle -- two new function `simgui_make_image()` and `simgui_destroy_image()` to - create and destroy such a new `simgui_image_t` object. -- the existing function `simgui_imtextureid()` has been changed to take - an `simgui_image_t` -- sokol_imgui.h now also uses the same error-handling and logging callback - as the other sokol headers (this was needed because creating an `simgui_image_t` - object may fail because the object pool is exhausted) - don't forget - to provide a logging callback (for instance via sokol_log.h), otherwise - sokol_imgui.h will be entirely silent in case of errors. - -Please also read the new documentation section `ON USER-PROVIDED IMAGES AND SAMPLERS` -in sokol_imgui.h, and also check out the new sample: - -https://floooh.github.io/sokol-html5/imgui-images-sapp.html - -Associated PR: https://github.com/floooh/sokol/pull/861 - -#### 16-Jul-2023 - -**BREAKING CHANGES** - -The main topic of this update is to separate sampler state from image state in -sokol_gfx.h which became possible after GLES2 support had been removed from -sokol_gfx.h. - -This also causes some 'collateral changes' in shader authoring and -other sokol headers, but there was opportunity to fill a few feature gaps -in sokol_gfx.h as well: - -- it's now possible to sample depth textures in shaders both with regular - samplers, and with 'comparison samplers' (which is mainly useful for shadow mapping) -- it's now possible to create render passes without color attachments for - 'depth-only' rendering - -See the new [shadows-depthtex-sapp](https://floooh.github.io/sokol-html5/shadows-depthtex-sapp.html) sample which demonstrates both features. - -> NOTE: all related projects have a git tag `pre-separate-samplers` in case you are not ready yet to make the switch - -> NOTE 2: if you use sokol-gfx with the sokol-shdc shader compiler, you'll also need -> to update the sokol-shdc binaries from https://github.com/floooh/sokol-tools-bin - -##### **sokol_gfx.h** - -- texture sampler state has been removed from `sg_image_desc`, instead you now - need to create separate sampler objects: - - ```c - sg_sampler smp = sg_make_sampler(&(sg_sampler_desc){ - .min_filter = SG_FILTER_LINEAR, - .mag_filter = SG_FILTER_LINEAR, - .wrap_u = SG_WRAP_CLAMP_TO_EDGE, - .wrap_v = SG_WRAP_CLAMP_TO_EDGE - }); - ``` - -- texture filtering is now described by 3 separate filters: - - min_filter = SG_FILTER_NEAREST | SG_FILTER_LINEAR - - mag_filter = SG_FILTER_NEAREST | SG_FILTER_LINEAR - - mipmap_filter = SG_FILTER_NONE | SG_FILTER_NEAREST | SG_FILTER_LINEAR - - ...this basically switches from the esoteric GL convention to a convention - that's used by all other 3D APIs. There's still a limitation that's caused by - GL though: a sampler which is going to be used with an image that has a - `mipmap_count = 1` requires that `.mipmap_filter = SG_FILTER_NONE`. - -- another new sampler state in `sg_sampler_desc` is `sg_compare_func compare;`, - this allows to create 'comparison samplers' for shadow mapping - -- when calling `sg_apply_bindings()` the struct `sg_bindings` now has changed - to also include sampler objects, note that there is no 1:1 relationship - between images and samplers required: - - ```c - sg_apply_bindings(&(sg_bindings){ - .vertex_buffers[0] = vbuf, - .fs = { - .images = { - [SLOT_tex0] = img0, - [SLOT_tex1] = img1, - [SLOT_tex2] = img2, - }, - .samplers[SLOT_smp] = smp, - } - }); - ``` - -- if you use sokol-shdc, you need to rewrite your shaders from 'OpenGL GLSL style' (with - combined image samplers) to 'Vulkan GLSL style' (with separate textures and samplers): - - E.g. the old GL-style shader with combined image samplers: - - ```glsl - uniform sampler2D tex; - - void main() { - frag_color = texture(tex, uv); - } - ``` - ...now needs to look like this: - - ```glsl - uniform texture2D tex; - uniform sampler smp; - - void main() { - frag_color = texture(sampler2D(tex, smp), uv); - } - ``` - - sokol-shdc will now throw an error if it encounters an 'old' shader using combined - image-samplers, this helps you to catch all places where a rewrite to separate - texture and sampler objects is required. - -- If you *don't* use sokol-shdc and instead provide your own backend-specific - shaders, you need to provide more shader interface reflection info about the texture - and sampler usage in a shader when calling `sg_make_shader`. - Please see the new documentation block `ON SHADER CREATION` in sokol_gfx.h for more details! - - Also refer to the updated 3D-backend-specific samples here: - - - for GL: https://github.com/floooh/sokol-samples/tree/master/glfw - - for GLES3: https://github.com/floooh/sokol-samples/tree/master/html5 - - for D3D11: https://github.com/floooh/sokol-samples/tree/master/d3d11 - - for Metal: https://github.com/floooh/sokol-samples/tree/master/metal - -- it's now possible to create `sg_pass` objects without color attachments to - enable depth-only rendering, see the new sample [shadows-depthtex-sapp](https://floooh.github.io/sokol-html5/shadows-depthtex-sapp.html) for details, - specifically be aware of the caveat that a depth-only-compatible `sg_pipeline` object - needs to 'deactivate' the first color target by setting its pixel format - to `NONE`: - - ```c - sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){ - ... - .colors[0].pixel_format = SG_PIXELFORMAT_NONE, - ... - }); - ``` - -- the following struct names have been changed to be more in line with related - struct names, this also makes those names similar to WebGPU types: - - - `sg_buffer_layout_desc` => `sg_vertex_buffer_layout_state` - - `sg_vertex_attr_desc` => `sg_vertex_attr_state` - - `sg_layout_desc` => `sg_vertex_layout_state` - - `sg_color_state` => `sg_color_target_state` - -- bugfixes and under-the-hood changes - - `sg_begin_pass()` used the wrong framebuffer size when rendering to a mip-level != 0 - - the Metal backend code started to use the `if (@available(...))` statement - to check for runtime-availability of macOS/iOS API features - - **NOTE:** this change (`if (@available(...))`) caused linking problems in - the Zig and Rust bindings on GH Actions (missing symbol - `___isPlatformVersionAtLeast`) which I could not reproduce locally on my - M1 Mac. On Zig this could be fixed by moving to the latest zig-0.11.0-dev - version, but for Rust this still needs to be fixed). - - on macOS the Metal backend now creates resources in Shared resource storage mode if - supported by the device - - on iOS the Metal backend now supports clamp-to-border-color if possible (depends on - iOS version and GPU family) - -##### **sokol_gl.h** - -- The function `sgl_texture(sg_image img)` has been changed to accept a sampler - object to `sgl_texture(sg_image img, sg_sampler smp)`. Passing an invalid image handle - will use the builtin default (white) texture, and passing an invalid sampler - handle will use the builtin default sampler. - -##### **sokol_shape.h** - -- Some sokol-shape functions have been renamed to match renamed structs in sokol-gfx: - - - `sshape_buffer_layout_desc()` => `sshape_vertex_buffer_layout_state()` - - `sshape_position_attr_desc()` => `sshape_position_vertex_attr_state()` - - `sshape_normal_attr_desc()` => `sshape_normal_vertex_attr_state()` - - `sshape_texcoord_attr_desc()` => `sshape_texcoord_vertex_attr_state()` - - `sshape_color_attr_desc()` => `sshape_color_vertex_attr_state()` - -##### **sokol_spine.h** - -- A sokol-spine atlas object now allocates both an `sg_image` and `sg_sampler` handle - and expects the user code to initialize those handles to complete image and - sampler objects. Check the updated sokol-spine samples here for more details: - - https://github.com/floooh/sokol-samples/tree/master/sapp - -##### **sokol_imgui.h** - -- sokol_imgui.h has a new public function to create an ImTextureID handle from - an `sg_image` handle which can be used like this: - - ```c - ImTextureID tex_id = simgui_imtextureid(img); - ``` - - Note that sokol-imgui currently doesn't currently allow to pass user-provided `sg_sampler` - object with the user-provided image. - -##### **sokol_nuklear.h** - -- similar to sokol_imgui.h, there's a new public function `snk_nkhandle()` - which creates a Nuklear handle from a sokol-gfx image handle which can be - used like this to create a Nuklear image handle: - - ```c - nk_image nki = nk_image_handle(snk_nkhandle(img)); - ``` - - As with sokol_imgui.h, it's currently not possible to pass a user-provided `sg_sampler` - object with the image. - - -#### 20-May-2023 - -Some minor event-related cleanup in sokol_app.h and a touchscreen fix in sokol_imgui.h - -- in the event `SAPP_EVENTTYPE_FILESDROPPED`: - - the `sapp_event.modifier` field now contains the active modifier keys - at the time of the file drop operations on the platforms macOS, Emscripten - and Win32 (on Linux I haven't figured out how this might work with the - Xlib API) - - on macOS, the `sapp_event.mouse_x/y` fields now contain the window-relative - mouse position where the drop happened (this already worked as expected on - the other desktop platforms) - - on macOS and Linux, the `sapp_event.mouse_dx/dy` fields are now set to zero - (this already was the case on Emscripten and Win32) -- in the events `SAPP_EVENTTYPE_MOUSE_ENTER` and `SAPP_EVENTTYPE_MOUSE_LEAVE`: - - the `sapp_event.mouse_dx/dy` fields are now set to zero, previously this - could be a very big value on some desktop platforms - -Many thanks to @castano for the initial PR (https://github.com/floooh/sokol/pull/830)! - -- In sokol_imgui.h, the new io.AddMouseSourceEvent() function in Dear ImGui 1.89.5 - is called to differentiate between mouse- and touch-events, this makes ui tabs - work with a single tap (previously a double-tap on the tab was needed). The code - won't break if the ImGui version is older (in this case the function simply isn't called) - - -#### 19-May-2023 - -**BREAKING CHANGES**_ in sokol_gfx.h: Render passes are now more 'harmonized' -with Metal and WebGPU by exposing a 'store action', and making MSAA resolve attachments -explicit. The changes in detail: - - - A new documentation section `ON RENDER PASSES` has been added to sokol_gfx.h, this - gives a much more detailed overview of the new render pass behaviour than this - changelog, please make sure to give it a read - especially when you are using - MSAA offscreen render passes in your code. - - `sg_action` has been renamed to `sg_load_action`. - - A new enum `sg_store_action` has been added. - - In `sg_pass_action`: - - `.action` has been renamed to `.load_action`. - - `.value` has been renamed to `.clear_value`. - - A new field `.store_action` has been added. - - An `sg_image` object with a sample count > 1 no longer contains a second implicit - texture for the msaa-resolve operation. - - When creating a pass object, there's now an array of `sg_image` objects - called `resolve_attachments[]`. When a resolve attachment image is set, the - color attachment at the same slot index must be an image with a sample count > - 1, and an 'msaa-resolve' operation from the color attachment into the - resolve attachment will take place in `sg_end_pass()`. - - Pass attachments are now more flexible (there were a couple of gaps where specific - image types were not allowed as pass attachments, especially for the depth-stencil- - attachment - but this hadn't actually been checked by the validation layer). - - Some gaps in the validation layer around images and passes have been tightened up, - those usually don't work in one backend or another, but have been ignored so far - in the validation layer, mainly: - - MSAA images must have num_mipmaps = 1. - - 3D images cannot have a sample_count > 1. - - 3D images cannot have depth or depth-stencil image formats. - - It's not allowed to bind MSAA images as texture. - - It's not allowed to bind depth or depth-stencil images as texture. - - (I'll see if I can relax some of those restrictions after the WebGPU backend release) - - **A lot** of new tests have been added to cover validation layer checks when creating - image and pass objects. - - Next up: WebGPU! - -#### 30-Apr-2023 - -GLES2/WebGL1 support has been removed from the sokol headers (now that - all browsers support WebGL2, and WebGPU is around the corner I feel like it's finally - time to ditch GLES2. - - This is a breaking API change in sokol_gfx.h and sokol_app.h. - - Common changes across all headers: - - (breaking change) the `SOKOL_GLES2` config define is no longer accepted and will cause a compile error - (use `SOKOL_GLES3` instead) - - (breaking change) on Emscripten use the linker option `-s USE_WEBGL2=1` - - any embedded GLES shaders have been updated from glsl100 to glsl300es (but glsl100 shaders - still work fine with the GLES3 backend) - - Changes in sokol_gfx.h: - - (breaking change) the following `sg_features` members have been removed (because those features - are no longer optional, but guaranteed across all backends): - - `sg_features.instancing` - - `sg_features.multiple_render_targets` - - `sg_features.msaa_render_targets` - - `sg_features.imagetype_3d` - - `sg_features.imagetype_array` - - (breaking change) the struct `sg_gl_context_desc` and its embedded instance `sg_desc.gl` have been removed - - `sg_image` objects with `SG_PIXELFORMAT_DEPTH` or `SG_PIXELFORMAT_DEPTH_STENCIL` with - a `sample_count == 1` are now regular textures in the GL backend (this is not true - for MSAA depth textures unfortunately, those are still GL render buffer objects) - - in the GL backend, `SG_PIXELFORMAT_DEPTH` now resolves to `GL_DEPTH_COMPONENT32F` (same - as in the other backends), previously it was `GL_DEPTH_COMPONENT16` - - in `sg_begin_pass()`, the GL backend now only uses the new `glClearBuffer*` functions, the - old GLES2 clear functions have been removed - - in `sg_end_pass()`, the GLES3 backend now invalidates MSAA render buffers after they have - been resolved (via `glInvalidateFramebuffer`) - more control over this will come soon-ish - when this ticket is implemented: https://github.com/floooh/sokol/issues/816 - - the instanced rendering functions are no longer wrapped in C macros in the GL backend - - Changes in sokol_app.h: - - (breaking) the config item `sapp_desc.gl_force_gles2` has been removed - - (breaking) the function `sapp_gles2()` has been removed - - any fallback logic from GLES3 to GLES2 has been removed (in the Emscripten, Android and - iOS backends) - -- **20-Feb-2023**: sokol_gfx.h has a new set of functions to get a 'best-effort' - desc struct with the creation parameters of a specific resource object: - - ```c - sg_buffer_desc sg_query_buffer_desc(sg_buffer buf); - sg_image_desc sg_query_image_desc(sg_image img); - sg_shader_desc sg_query_shader_desc(sg_shader shd); - sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip); - sg_pass_desc sg_query_pass_desc(sg_pass pass); - ``` - - The returned structs will *not* be an exact copy of the desc struct that - was used for creation the resource object, instead: - - - references to external data (like buffer and image content or - shader sources) will be zeroed - - any attributes that have not been kept around internally after - creation will be zeroed (the ```sg_shader_desc``` struct is most - affected by this, the other structs are fairly complete). - - Calling the functions with an invalid or dangling resource handle - will return a completely zeroed struct (thus it may make sense - to first check the resource state via ```sg_query_*_state()```) - - Nevertheless, those functions may be useful to get a partially filled out - 'creation blueprint' for creating similar resources without the need - to keep and pass around the original desc structs. - - >MINOR BREAKING CHANGE: the struct members ```sg_image_info.width``` and - ```sg_image_info.height``` have been removed, this information is now - returned by ```sg_query_image_desc()```. - - PR: https://github.com/floooh/sokol/pull/796, fixes: https://github.com/floooh/sokol/issues/568 - -- **17-Feb-2023**: sokol_app.h on macOS now has a proper fix for the problem - that macOS doesn't send key-up events while the Cmd key is held down. - Previously this was handled through a workaround of immediately sending a - key-up event after its key-down event if the Cmd key is currently held down - to prevent a 'stuck key'. The proper fix is now to install an "event monitor" - callback (many thanks to GLFW for finding and implementing the solution). - Unfortunately there's no such solution for the Emscripten code path, which - also don't send a key-up event while Cmd is pressed on macOS (the workaround - there to send a key-up event right on key-down while Cmd is held down to - prevent a stuck key is still in place) For more details, see: - https://github.com/floooh/sokol/issues/794 - -- **15-Feb-2023**: A fix in the sokol_gfx.h GL backend: due to a bug in the - state cache, the GL backend could only bind a total of - SG_MAX_SHADERSTAGE_IMAGES (= 12) when it actually should be twice that amount - (12 per shader stage). Note however that the total amount of texture bindings - is still internally limited by the GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - runtime variable (~~currently this is not exposed in sg_limits though~~). Many - thanks to @allcreater for PR https://github.com/floooh/sokol/pull/787. - PS: sg_limits now exposes GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS as - ```sg_limits.gl_max_combined_texture_image_units```, and the - value can also be inspected via the debug UI in sokol_gfx_imgui.h. - -- **13-Feb-2023**: The way logging works has been completely revamped in - the sokol headers. UWP support has been removed from sokol_audio.h - and sokol_app.h (this also means that the sokol headers no longer contain - any C++ code). - - **REQUIRED ACTION**: Since the sokol headers are now completely silent - without a logging callback (explanation below), it is highly recommended - to use the standard logging callback provided by the new header ```sokol_log.h```. - For instance for sokol_gfx.h it looks like this: - - ```c - #include "sokol_log.h" - //... - sg_setup(&(sg_desc){ - //... - .logger.func = slog_func, - }); - ``` - - All sokol samples have been updated to use sokol_log.h for logging. - - The former logging callback is now a combined - logging- and error-reporting callback, and more information is available - to the logging function: - - a 'tag string' which identifies the sokol headers, this string - is identical with the API prefix (e.g. "sg" for sokol_gfx.h, - "sapp" for sokol_app.h etc...) - - a numeric log level: 0=panic, 1=error, 2=warning, 3=info - - a numeric 'log item id' (think of it as error code, but since - not only errors are reported I called it a log item id) - - a human readable error message - - a source file line number where the log item was reported - - the file path of the sokol header - - Log level ```panic``` is special in that it terminates execution inside - the log function. When a sokol header issues a panic log message, it means - that the problem is so big that execution can not continue. By default, - the sokol headers and the standard log function in sokol_log.h call - ```abort()``` when a panic log message is issued. - - In debug mode (NDEBUG not defined, or SOKOL_DEBUG defined), a log message - (in this case from sokol_spine.h) will look like this: - - ``` - [sspine][error][id:12] /Users/floh/projects/sokol/util/sokol_spine.h:3472:0: - SKELETON_DESC_NO_ATLAS: no atlas object provided in sspine_skeleton_desc.atlas - ``` - The information can be 'parsed' like this: - - ```[sspine]```: it's a message from sokol_spine.h - - ```[error]```: it's an error - - ```[id:12]```: the numeric log item id (associated with ```SKELETON_DESC_NO_ATLAS``` below) - - source file path and line number in a compiler-specific format - in some IDEs and terminals - this is a clickable link - - the line below is the human readable log item id and message - - In release mode (NDEBUG is defined and SOKOL_DEBUG is not defined), log messages - are drastically reduced (the reason is to not bloat the executable with all the extra string data): - - ``` - [sspine][error][id:12][line:3472] - ``` - ...this reduced information still gives all the necessary information to identify the location and type of error. - - A custom logging function must adhere to a few rules: - - - must be re-entrant because it might be called from different threads - - must treat **all** provided string pointers as optional (can be null) - - don't store the string pointers, copy the string data instead - - must not return for log level panic - - A new header ```sokol_log.h``` has been added to provide a standard logging callback implementation - which provides logging output on all platforms to stderr and/or platform specific logging - facilities. ```sokol_log.h``` only uses fputs() and platform specific logging function instead - of fprintf() to preserve some executable size. - - **QUESTION**: Why are the sokol headers now silent, unless a logging callback is installed? - This is mainly because a standard logging function which does something meaningful on all - platforms (including Windows and Android) isn't trivial. E.g. printing to stderr is not - enough. It's better to move that stuff into a centralized place in a separate header, - but since the core sokol headers must not (statically) depend on other sokol headers - the only solution that made sense was to provide a standard logging function which must - be 'registered' as a callback. - -- **26-Jan-2023**: Work on SRGB support in sokol_gfx.h has started, but - this requires more effort to be really usable. For now, only a new - pixel format has been added: SG_PIXELFORMAT_SRGB8A8 (see https://github.com/floooh/sokol/pull/758, - many thanks to @allcreater). The sokol-gfx GL backend has a temporary - workaround to align behaviour with D3D11 and Metal: automatic SRGB conversion - is enabled for offscreen render passes, but disabled for the default - framebuffer. A proper fix will require separate work on sokol_app.h to - support an SRGB default framebuffer and communicate to sokol-gfx - whether the default framebuffer is SRGB enabled or not. - -- **24-Jan-2023**: sokol_gfx.h Metal: A minor inconsistency has been fixed in - the validation layer and an assert for the function ```sg_apply_uniforms()``` - which checks the size of the incoming data against the uniform block size. - The validation layer and Metal backend did a ```<=``` test while the D3D11 - and GL backends checked for an exact size match. Both the validation layer - and the Metal backend now also check for an exact match. Thanks to @nmr8acme - for noticing the issue and providing a PR! (https://github.com/floooh/sokol/pull/776) - -- **23-Jan-2023**: A couple more sokol_audio.h updates: - - an AAudio backend has been added for Android, and made the default. This - means you now need to link with ```aaudio``` instead of ```OpenSLES``` when - using sokol_audio.h on Android. The OpenSLES backend code still exists (for - now), but must be explicitly selected by compiling the sokol_audio.h - implementation with the define ```SAUDIO_ANDROID_SLES``` (e.g. there is - no runtime fallback from AAudio to OpenSLES). AAudio is fully supported - since Android 8.1. Many thanks to @oviano for the initial AAudio PR - (https://github.com/floooh/sokol/pull/484) - - in the WebAudio backend, WebAudio is now properly activated on the first - input action again on Chrome for Android (at some point activating WebAudio - via a ```touchstart``` event stopped working and had to be moved to the - ```touchend``` event, see https://github.com/floooh/sokol/issues/701) - - audio backend initialization on iOS and macOS is now a bit more fault-tolerant, - errors during initialization now properly set sokol_audio.h to 'silent mode' - instead of asserting (or in release mode ignoring the error) - - ...and some minor general code cleanup things in sokol_audio.h: backend-specific - functions now generally have a matching prefix (like ```_saudio_alsa_...()```) - for better searchability - -- **16-Jan-2023**: - - sokol_audio.h android: https://github.com/floooh/sokol/pull/747 has been merged - which adds a couple more error checks at OpenSLES startup. - - sokol_gfx.h: support for half-float vertex formats has been added via - PR https://github.com/floooh/sokol/pull/745 - - sokol_imgui.h: fixes for Dear ImGui 1.89 deprecations (via PR https://github.com/floooh/sokol/pull/761) - -- **15-Jan-2023**: two bugfixes in sokol_app.h and sokol_gfx.h: - - sokol_app.h x11: Mouse button events now always return valid mouse - coordinates, also when no mouse movement happened yet - (fixes https://github.com/floooh/sokol/issues/770) - - sokol_gfx.h gl: The GL context is now configured with - GL_UNPACK_ALIGNMENT = 1, this should bring texture creation and updating - behaviour in line with the other backends for tightly packed texture - data that doesn't have a row-pitch with a multiple of 4 - (fixes https://github.com/floooh/sokol/issues/767) - -- **14-Jan-2023**: sokol_app.h x11: a drag'n'drop related bugfix, the - XdndFinished reply event was sent with the wrong window handle which - confused some apps where the drag operation originated - (see https://github.com/floooh/sokol/pull/765#issuecomment-1382750611) - -- **16-Dec-2022**: In the sokol_gfx.h Metal backend: A fix for a Metal - validation layer error which I just discovered yesterday (seems to be new in - macOS 13). When the validation layer is active, and the application window - becomes fully obscured, the validation layer throws an error after a short - time (for details see: https://github.com/floooh/sokol/issues/762). - The reason appears to be that sokol_gfx.h creates a command buffer with - 'unretained references' (e.g. the command buffer doesn't manage the - lifetime of resources used by the commands stored in the buffer). This - seems to clash with MTKView's and/or CAMetalLayer's expectations. I fixed - this now by creating a second command buffer with 'retained references', - which only holds the ```presentDrawable``` command. That way, regular - draw commands don't have the refcounting overhead (because they're stored - in an unretained-references cmdbuffer), while the drawable surface is - still properly lifetime managed (because it's used in a separate command - buffer with retained references). - -- **15-Dec-2022**: A small but important update in sokol_imgui.h which fixes - touch input handling on mobile devices. Many thanks to github user @Xadiant - for the bug investigation and [PR](https://github.com/floooh/sokol/pull/760). - -- **25-Nov-2022**: Some code cleanup around resource creation and destruction in sokol_gfx.h: - - It's now safe to call the destroy, uninit and dealloc functions in any - resource state, in general, the functions will do the right thing without - assertions getting in the way (there are however new log warnings in some - cases though, such as attempting to call an ```sg_dealloc_*()``` function on - a resource object that's not in ALLOC state) - - A related **minor breaking change**: the ```sg_uninit_*()``` functions now return - void instead of bool, this is because ```sg_dealloc_*()``` no longer asserts - when called in the wrong resource state - - Related internal code cleanup in the backend-agnostic resource creation - and cleanup code, better or more consistent function names, etc... - - The validation layer can now be disabled in debug mode with a runtime - flag during setup: ```sg_desc.disable_validation```. This is mainly useful - for test code. - - Creating a pass object with invalid image objects now no longer asserts, - but instead results in a pass object in FAILED state. In debug mode, - the validation layer will still stop at this problem though (it's mostly - an 'undefined API behaviour' fix in release mode). - - Calling ```sg_shutdown()``` with existing resources in ALLOC state will - no longer print a log message about an 'active context mismatch'. - - A new header documentation blurb about the two-step resource creation - and destruction functions (search for RESOURCE CREATION AND DESTRUCTION IN DETAIL) - -- **16-Nov-2022**: Render layer support has been added to sokol_debugtext.h, - same general changes as in sokol_gl.h with two new functions: - sdtx_layer(layer_id) to select the layer to record text into, and - sdtx_draw_layer(layer_id) to draw the recorded text in that layer inside a - sokol-gfx render pass. The new sample [debugtext-layers-sapp](https://floooh.github.io/sokol-html5/debugtext-layers-sapp) demonstrates the feature together with - sokol-gl. - - -- **11-Nov-2022**: sokol_gl.h has 2 new public API functions which enable - layered rendering: sgl_layer(), sgl_draw_layer() (technically it's three - functions: there's also sgl_context_draw_layer(), but that's just a variant of - sgl_draw_layer()). This allows to 'interleave' sokol-gl rendering - with other render operations. The [spine-layers-sapp](https://floooh.github.io/sokol-html5/spine-layers-sapp.html) - sample has been updated to use multiple sokol-gl layers. - -- **09-Nov-2022**: sokol_gfx.h now allows to add 'commit listeners', these - are callback functions which are called from inside sg_commit(). This is - mainly useful for libraries which build on top of sokol-gfx to be notified - about the start/end point of a frame, which in turn may simplify the public - API, or the internal implementation, because the library no longer needs to - 'guess' when a new frame starts. - - For more details, search for 'COMMIT LISTENERS' in the sokol_gfx.h header. - - This also results in a minor breaking change in sokol_spine.h: The function - ```sspine_new_frame()``` has been removed and replaced with an internal commit - listener. - - Likewise, sokol_gl.h now uses a commit listener in the implementation, but - without changing the public API (the feature will be important for an upcoming - sokol-gl feature to support rendering layers, and for this a 'new-frame-function' - would have been needed). - -- **05-Nov-2022** A breaking change in sokol_fetch.h, and a minor change in - sokol_app.h which should only break for very few users: - - An ```sfetch_range_t``` ptr/size pair struct has been added to sokol_fetch.h, - and discrete ptr/size pairs have been replaced with sfetch_range_t - items. This affects the structs ```sfetch_request_t``` and ```sfetch_response_t```, - and the function ```sfetch_bind_buffer()```. - - The required changes in ```sfetch_response_t``` might be a bit non-obviois: To - access the fetched data, previous ```.buffer_ptr``` and ```.fetched_size``` - was used. The fetched data is now accessible through an ```sfetch_range_t data``` - item (```data.ptr``` and ```data.size```). The old ```.fetched_offset``` item - has been renamed to ```.data_offset``` to better conform with the new naming. - - The last two occurrences of discrete ptr/size pairs in sokol_app.h now have also - been replaced with ```sapp_range_t``` items, this only affects the structs - ```sapp_html5_fetch_request``` and ```sapp_html5_fetch_response```. - -- **03-Nov-2022** The language bindings generation has been updated for Zig 0.10.0, - and clang-14 (there was a minor change in the JSON ast-dump format). - Many thanks to github user @kcbanner for the Zig PR! - -- **02-Nov-2022** A new header sokol_spine.h (in the util dir), this is a - renderer and 'handle wrapper' around the spine-c runtime (Spine is a popular 2D - character anim system: http://esotericsoftware.com/). This turned out a much bigger - rabbit-hole than I initially expected, but the effort is justified by being a - experimentation testbed for a couple of things I want to add to other sokol - headers (for instance cleaned up handle pool code, a new logging- and error-reporting - system, render layers which will be useful for sokol_gl.h and sokol_debugtext.h). - -- **22-Oct-2022** All sokol headers now allow to override logging with a - callback function (installed in the setup call) instead of defining a SOKOL_LOG - macro. Overriding SOKOL_LOG still works as default fallback, but this is no - longer documented, consider this deprecated. Many thanks to github user - @Manuzor for the PR (see https://github.com/floooh/sokol/pull/721 for details) - -- **21-Oct-2022** RGB9E5 pixel format support in sokol_gfx.h and a GLES2 related - bugfix in the sokol_app.h Android backend: - - sokol_gfx.h now supports RGB9E5 textures (3*9 bit RGB + 5 bit shared exponent), - this works in all backends except GLES2 and WebGL1 (use ```sg_query_pixelformat()``` - to check for runtime support). Many thanks to github user @allcreater for the PR! - - a bugfix in the sokol_app.h Android backend: when forcing a GLES2 context via - sapp_desc.gl_force_gles2, the Android backend correctly created a GLES2 context, - but then didn't communicate this through the function ```sapp_gles2()``` (which - still returned false in this case). This caused the sokol_gfx.h GL backend to - use the GLES3 code path instead GLES2 (which surprisingly seemed to have worked - fine, at least for the sokol samples which force GLES2). - -- **19-Oct-2022** Some fixes in the embedded Javascript code blocks (via EM_JS) - in sokol_app.h, sokol_args.h, sokol_audio.h and sokol_fetch.h: - - the JS code has been 'modernized' (e.g. const and let instead of var, - ```() => { ... }``` instead of ```function () { ... }``` for callbacks) - - false positives in the Closure static analysis have been suppressed - via inline hints - -- **16-Oct-2022** The Odin bindings generator and the generated bindings have - been simplified (the Odin binding now don't have separate wrapper functions). - Requires the latest Odin release. Also note: On M1 Macs I'm currently seeing - what looks like an ABI problem (in functions which pass color values to the C - side as uint8_t, the colors come out wrong). This also happened with the - previous binding version, so it looks like a regression in Odin. Might be - related to this recent bugfix (which I haven't tested yet): - https://github.com/odin-lang/Odin/issues/2121 Many thanks to @thePHTest for the - PR! (https://github.com/floooh/sokol/pull/719) - -- **15-Oct-2022** - - fixes for Emscripten 3.1.24: the sokol headers now use the new - **EM_JS_DEPS()** macro to declare 'indirect dependencies on JS library functions'. - This is a (much more robust) follow-up fix to the Emscripten related fixes from 10-Sep-2022. - The new Emscripten SDK also displays a couple of Javascript "static analyzer" warnings - by the Closure compiler (used in release mode to optimize and minify the generated - JS code). I fixed a couple of those warnings, but some warnings persist (all of them - false positives). Not sure yet if these can be fixed or need to be suppressed, but - that's for another time. - - the webkitAudioContext() fallback in sokol_audio.h's Emscripten backend - has been removed (only AudioContext is supported now), the fallback also - triggered a Closure warning, so it probably never worked as intended anyway. - - I also had to undo an older workaround in sokol_app.h on iOS (https://github.com/floooh/sokol/issues/645) - because this is now triggering a Metal validation layer error (https://github.com/floooh/sokol/issues/726). - The original case is no longer reproducible, so undoing the old workaround seems to - be a quick fix. Eventually I want to get rid of MTKView though, and go down to - CAMetalLayer. - -- **08-Oct-2022** sokol_app.h Android backend: the ```sapp_touchpoint``` struct - now has a new item ```sapp_android_tooltype android_tooltype;```. This exposes the - result of the Android NDK function ```AMotionEvent_getToolType()```. - Many thanks to @Wertzui123 for the initial PR (https://github.com/floooh/sokol/pull/717). - -- **25-Sep-2022**: sokol_app.h on Linux now optionally supports EGL instead of - GLX for the window system glue code and can create a GLES2 or GLES3 context - instead of a 'desktop GL' context. - To get EGL+GLES2/GLES3, just define SOKOL_GLES2 or SOKOL_GLES3 to compile the - implementation. To get EGL+GL, define SOKOL_GLCORE33 *and* SOKOL_FORCE_EGL. - By default, defining just SOKOL_GLCORE33 uses GLX for the window system glue - (just as before). Many thanks to GH user @billzez for the PR! - -- **10-Sep-2022**: sokol_app.h and sokol_args.h has been fixed for Emscripten 3.21, those headers - used the Emscripten Javascript helper function ```ccall()``` which is now part of the - 'legacy runtime' and causes linker errors. Instead of ```ccall()``` sokol_app.h and sokol_args.h - now drop down to a lower level set of Emscripten JS helper functions (which hopefully won't - go away anytime soon). - -- **05-Aug-2022**: New officially supported and automatically updated language bindings for Odin: - https://github.com/floooh/sokol-odin (also see [gen_odin.py](https://github.com/floooh/sokol/blob/master/bindgen/gen_odin.py)) - -- **10-Jul-2022**: New features in sokol_app.h and sokol_imgui.h: - - In sokol_app.h it's now possible to set a mouse cursor type from a number of predefined - types via the new function ```sapp_set_mouse_cursor(sapp_mouse_cursor cursor)```. The - available cursor types are compatible with GLFW and Dear ImGui. Supported platforms - are: macOS, linux, win32, uwp and web. - - ```sapp_show_mouse(bool shown)``` now also works on the web platform. - - In sokol_app.h, the poorly defined 'user cursor' feature has been removed (```sapp_desc.user_cursor``` - and ```SAPP_EVENTTYPE_UPDATE_CURSOR```). This was a hack to allow changing the mouse cursor and - only worked on Win32 and macOS (with different behaviour). Since setting the cursor type - is now 'properly supported, this hack was removed. - - sokol_imgui.h will now set the cursor type via ```sapp_set_mouse_cursor()```. This can be - disabled with the new ```simgui_desc_t``` item ```disable_set_mouse_cursor```. - - sokol_imgui.h now automatically enables resizing windows from edges (not just the bottom-right corner), - this behaviour can be disabled with the new ```simgui_desc_t``` item ```disable_windows_resize_from_edges```. - - sokol_imgui.h can now optionally write to the alpha channel (useful if you want to render the UI - into a separate render target, which is later composed onto the default framebuffer). The feature - is enabled with the new ```simgui_desc_t``` item ```write_alpha_channel```. - - Many thanks to **@tomc1998** for the initial [Linux/X11 mouse cursor type PR](https://github.com/floooh/sokol/pull/678) and - **@luigi-rosso** for the [sokol_imgui.h alpha channel PR](https://github.com/floooh/sokol/pull/687)! - -- **03-Jul-2022**: A new sokol_gfx.h function ```bool sg_query_buffer_will_overflow(sg_buffer buf, size_t size)``` -which allows to check if a call to ```sg_append_buffer()``` would overflow the buffer. This -is an alternative to the ```sg_query_buffer_overflow()``` function which only reports -the overflow after the fact. Many thanks to @RandyGaul for the PR! - -- **29-Jun-2022**: In sokol_app.h with the D3D11 backend, if SOKOL_DEBUG is -defined, and the D3D11 device creation fails, there's now a fallback code -path which tries to create the device again without the D3D11_CREATE_DEVICE_DEBUG -flag. Turns out the D3D11 debug support may suddenly stop working (just happened -to me, indicated by the Win10 "Graphics Tool" feature being silently uninstalled -and failing to install when asked to do so). This fix at least allows sokol_app.h -applications compiled in debug mode to run, even if the D3D11 debug layer doesn't -work. - -- **29-May-2022**: The code generation scripts for the -[sokol-nim](https://github.com/floooh/sokol-nim) language bindings have been -revised and updated, many thanks to Gustav Olsson for the PR! (I'm planning to -spend a few more days integrating the bindings generation with Github Actions, -so that it's easier to publish new bindings after updates to the sokol headers). - -- **26-May-2022**: The GL backend in sokol_app.h now allows to override the GL - context version via two new items in the ```sapp_desc``` struct: - ```sapp_desc.gl_major_version``` and ```sapp_desc.gl_minor_version```. The - default GL context version remains at 3.2. Overriding the GL version might make - sense if you're not using sokol_app.h together with sokol_gfx.h, or otherwise - want to call GL functions directly. Note that this only works for the - 'desktop GL' backends (Windows, Linux and macOS), but not for the GLES backends - (Android, iOS, web). Furthermore, on macOS only the GL versions 3.2 and 4.1 - are available (plus the special config major=1 minor=0 creates an - NSOpenGLProfileVersionLegacy context). In general: use at your risk :) Many - thanks to Github user @pplux for the PR! - -- **15-May-2022**: The way internal memory allocation can be overridden with - your own functions has been changed from global macros to callbacks - provided in the API setup call. For instance in sokol_gfx.h: - - ```c - void* my_malloc(size_t size, void* userdata) { - (void)userdata; // unused - return malloc(size); - } - - void my_free(void* ptr, void* userdata) { - (void)userdata; // unused - free(ptr); - } - - //... - sg_setup(&(sg_desc){ - //... - .allocator = { - .alloc = my_malloc, - .free = my_free, - .user_data = ..., - } - }); - ``` - - sokol_gfx.h will now call ```my_malloc()``` and ```my_free()``` whenever it needs - to allocate or free memory (note however that allocations inside OS - functions or 3rd party libraries are not affected). - - If no override functions are provided, the standard library functions ```malloc()``` and ```free()``` - will be used, just as before. - - This change breaks source compatibility in the following headers: - - - **sokol_fontstash.h**: the function signature of ```sfons_create()``` has changed, - this now takes a pointer to a new ```sfons_desc_t``` struct instead of - individual parameters. - - **sokol_gfx_imgui.h** (NOT sokol_imgui.h!): likewise, the function signature of - ```sg_imgui_init()``` has changed, this now takes an additional parameter - which is a pointer to a new ```sg_imgui_desc_t``` struct. - - All affected headers also have a preprocessor check for the outdated - macros ```SOKOL_MALLOC```, ```SOKOL_CALLOC``` and ```SOKOL_FREE``` and throw - a compilation error if those macros are detected. - - (if configuration through macros is still desired this could be added back in - the future, but I figured that the new way is more flexible in most situations). - - The header sokol_memtrack.h and the sample [restart-sapp](https://floooh.github.io/sokol-html5/restart-sapp.html) have been updated accordingly. - - Also search for ```MEMORY ALLOCATION OVERRIDE``` in the header documentation block - for more details. - -- **14-May-2022**: added a helper function ```simgui_map_keycode()``` to - sokol_imgui.h to map sokol_app.h keycodes (```sapp_keycode```, - ```SAPP_KEYCODE_*```) to Dear ImGui keycodes (```ImGuiKey```, ```ImGuiKey_*```). - If you're using Dear ImGui function to check for key input, you'll need to - update the code like this: - - - Old: - ```cpp - ImGui::IsKeyPressed(SAPP_KEYCODE_A); - ``` - - New: - ```cpp - ImGui::IsKeyPressed(simgui_map_keycode(SAPP_KEYCODE_A)); - ``` - - This was basically 'fallout' from rewriting the input system in sokol_imgui.h - to the new evented IO system in Dear ImGui. - -- **08-Feb-2022**: sokol_imgui.h has been updated for Dear ImGui 1.87: - - sokol_imgui.h's input code has been rewritten to use the new evented IO - system and extended virtual key codes in Dear ImGui - - on non-Emscripten platforms, mouse buttons are no longer "cancelled" when - the mouse leaves the window (since the native desktop platforms - automatically capture the mouse when mouse buttons are pressed, but mouse - capture is not supported in the sokol_app.h Emscripten backend) - -- **28-Jan-2022**: some window size behaviour changes in sokol_app.h. - - Asking for a default-sized window (via sapp_desc.width/height = 0) now - behaves a bit differently on desktop platforms. Previously this set the - window size to 640x480, now a default window covers more screen area: - - on Windows CW_USEDEFAULT will be used for the size - - on macOS and Linux, the window size will be 4/5 of the - display size - - no behaviour changes on other platforms - - On Windows and Linux, the window is now centered (in a later update, - more control over the initial window position, and new functions for - positioning and sizing might be provided) - - On Windows, when toggling between windowed and fullscreen, the - window position and size will now be restored (on other platforms - this already happened automatically through the window system) - - On all desktop platforms if an application starts in fullscreen and - then is toggled back to windowed, the window will now be of the - expected size (provided in sapp_desc.width/height) - -- **20-Jan-2022**: - - sokol_audio.h: A compatibility fix in the sokol_audio.h WASAPI backend (Windows): On - some configs the IAudioClient::Initialize() call could fail because - of a mismatch between the requested number of channels and speaker config. - See [#614](https://github.com/floooh/sokol/issues/614) for details. - - sokol_app.h D3D11/DXGI: Fix an (uncritical) COM interface leak warning for IDXGIAdapter and - IDXGIFactory at shutdown, introduced with the recent disabling of Alt-Enter. - -- **18-Jan-2022**: - - sokol_app.h now has per-monitor DPI support on Windows and macOS: when - the application window is moved to a monitor with different DPI, the values - returned by sapp_dpi_scale(), sapp_width() and sapp_height() will update - accordingly (only if the application requested high-dpi rendering with - ```sapp_desc.high_dpi=true```, otherwise the dpi scale value remains - fixed at 1.0f). The application will receive an SAPP_EVENTTYPE_RESIZED event - if the default framebuffer size has changed because of a DPI change. - On Windows this feature requires Win10 version 1703 or later (aka the - 'Creators Update'), older Windows version simply behave as before. - Many thank to @tjachmann for the initial PR with the Windows implementation! - - sokol_app.h: DPI scale computation on macOS is now more robust using the - NSScreen.backingScaleFactor value - - sokol_app.h: the new frame timing code in sokol_app.h now detects if the display - refresh rate changes and adjusts itself accordingly (for instance if the - window is moved between displays with different refresh rate) - - sokol_app.h D3D11/DXGI: during window movement and resize, the frame is now - presented with DXGI_PRESENT_DO_NOT_WAIT, this fixes some window system - stuttering issues on Win10 configs with recent NVIDIA drivers. - - sokol_app.h D3D11/DXGI: the application will no longer appear to freeze for - 0.5 seconds when the title bar is grabbed with the mouse for movement, but - then not moving the mouse. - - sokol_app.h D3D11/DXGI: DXGI's automatic windowed/fullscreen switching via - Alt-Enter has been disabled, because this switched to 'real' fullscreen mode, - while sokol_app.h's fullscreen mode uses a borderless window. Use the - programmatic fullscreen/window switching via ```sapp_toggle_fullscreen()``` - instead. - - **BREAKING CHANGE** in sokol_imgui.h: because the applications' DPI scale - can now change at any time, the DPI scale value is now communicated to - sokol_imgui.h in the ```simgui_new_frame()``` function. This has been - changed to accept a pointer to a new ```simgui_frame_desc_t``` struct. - With C99, change the simgui_new_frame() call as follows (if also using - sokol_app.h): - ```c - simgui_new_frame(&(simgui_frame_desc_t){ - .width = sapp_width(), - .height = sapp_height(), - .delta_time = sapp_frame_duration(), - .dpi_scale = sapp_dpi_scale() - }); - ``` - On C++ this works: - ```c++ - simgui_new_frame({ sapp_width(), sapp_height(), sapp_frame_duration(), sapp_dpi_scale() }); - ``` - ...or in C++20: - ```c++ - simgui_new_frame({ - .width = sapp_width(), - .height = sapp_height(), - .delta_time = sapp_frame_duration(), - .dpi_scale = sapp_dpi_scale() - }); - ``` - - **KNOWN ISSUE**: the recent change in sokol-audio's WASAPI backend to directly consume - float samples doesn't appear to work on some configs (see [#614](https://github.com/floooh/sokol/issues/614)), - investigation is underway - -- **15-Jan-2022**: - - A bugfix in the GL backend for uniform arrays using the 'native' uniform block layout. - The bug was a regression in the recent 'uniform data handling' update. See - [PR #611](https://github.com/floooh/sokol/pull/611) for details, and this [new sample/test](https://github.com/floooh/sokol-samples/blob/master/glfw/uniformarrays-glfw.c). - Many thanks to @nmr8acme for the PR! - -- **08-Jan-2022**: some enhancements and cleanup to uniform data handling in sokol_gfx.h - and the sokol-shdc shader compiler: - - *IMPORTANT*: when updating sokol_gfx.h (and you're using the sokol-shdc shader compiler), - don't forget to update the sokol-shdc binaries too! - - The GLSL uniform types int, ivec2, ivec3 and - ivec4 can now be used in shader code, those are exposed to the GL - backends with the new ```sg_uniform_type``` items - ```SG_UNIFORM_TYPE_INT[2,3,4]```. - - A new enum ```sg_uniform_layout```, currently with the values SG_UNIFORMLAYOUT_NATIVE - and SG_UNIFORMLAYOUT_STD140. The enum is used in ```sg_shader_uniform_block_desc``` - as a 'packing rule hint', so that the GL backend can properly locate the offset - of uniform block members. The default (SG_UNIFORMLAYOUT_NATIVE) keeps the same - behaviour, so existing code shouldn't need to be changed. With the packing - rule SG_UNIFORMLAYOUT_STD140 the uniform block interior is expected to be - laid out according to the OpenGL std140 packing rule. - - Note that the SG_UNIFORMLAYOUT_STD140 only allows a subset of the actual std140 - packing rule: arrays are only allowed for the types vec4, int4 and mat4. - This is because the uniform data must still be compatible with - ```glUniform()``` calls in the GL backends (which have different - 'interior alignment' for arrays). - - The sokol-shdc compiler supports the new uniform types and will annotate the - code-generated sg_shader_desc structs with SG_UNIFORMLAYOUT_STD140, - and there are new errors to make sure that uniform blocks are compatible - with all sokol_gfx.h backends. - - Likewise, sokol_gfx.h has tighter validation for the ```sg_shader_uniform_block``` - desc struct, but only when the GL backend is used (in general, the interior - layout of uniform blocks is only relevant for GL backends, on all other backends - sokol_gfx.h just passes the uniform data as an opaque block to the shader) - For more details see: - - [new sections in the sokol_gfx.h documentation](https://github.com/floooh/sokol/blob/ba64add0b67cac16fc86fb6b64d1da5f67e80c0f/sokol_gfx.h#L343-L450) - - [documentation of ```sg_uniform_layout```](https://github.com/floooh/sokol/blob/ba64add0b67cac16fc86fb6b64d1da5f67e80c0f/sokol_gfx.h#L1322-L1355) - - [enhanced sokol-shdc documentation](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md#glsl-uniform-blocks-and-c-structs) - - [a new sample 'uniformtypes-sapp'](https://floooh.github.io/sokol-html5/uniformtypes-sapp.html) - - PS: and an unrelated change: the frame latency on Win32+D3D11 has been slightly improved - via IDXGIDevice1::SetMaximumFrameLatency() - -- **27-Dec-2021**: sokol_app.h frame timing improvements: - - A new function ```double sapp_frame_duration(void)``` which returns the frame - duration in seconds, averaged over the last 256 frames to smooth out - jittering spikes. If available, this uses platform/backend specific - functions of the swapchain API: - - On Windows: DXGI's GetFrameStatistics().SyncQPCTime. - - On Emscripten: the timestamp provided by the RAF callback, this will - still be clamped and jittered on some browsers, but averaged over - a number of frames yields a pretty accurate approximation - of the actual frame duration. - - On Metal, ```MTLDrawable addPresentedHandler + presentedTime``` - doesn't appear to function correctly on macOS Monterey and/or M1 Macs, so - instead mach_absolute_time() is called at the start of the MTKView - frame callback. - - In all other situations, the same timing method is used as - in sokol_time.h. - - On macOS and iOS, sokol_app.h now queries the maximum display refresh rate - of the main display and uses this as base to compute the preferred frame - rate (by multiplying with ```sapp_desc.swap_interval```), previously the - preferred frame rate was hardwired to ```60 * swap_interval```. This means - that native macOS and iOS applications may now run at 120Hz instead of - 60Hz depending on the device (I realize that this isn't ideal, there - will probably be a different way to hint the preferred interval at - which the frame callback is called, which would also support disabling - vsync and probably also adaptive vsync). - -- **19-Dec-2021**: some sokol_audio.h changes: - - on Windows, sokol_audio.h no longer converts audio samples - from float to int16_t, but instead configures WASAPI to directly accept - float samples. Many thanks to github user iOrange for the PR! - - sokol_audio.h has a new public function ```saudio_suspended()``` which - returns true if the audio device/context is currently in suspended mode. - On all backends except WebAudio this always returns false. This allows - to show a visual hint to the user that audio is muted until the first - input event is received. - -- **18-Dec-2021**: the sokol_gfx.h ```sg_draw()``` function now uses the currently applied - pipeline object to decide if the GL or D3D11 backend's instanced drawing function - should be called instead of the ```num_instances``` argument. This fixes a - bug on some WebGL configs when instanced rendering is configured - but ```sg_draw()``` is called with an instance count of 1. - -- **18-Nov-2021**: sokol_gl.h has a new function to control the point size for - point list rendering: ```void sgl_point_size(float size)```. Note that on D3D11 - the point size is currently ignored (since D3D11 doesn't support a point size at - all, the feature will need to be emulated in sokol_gl.h when the D3D11 backend is active). - Also note that points cannot currently be textured, only colored. - -- **08-Oct-2021**: texture compression support in sokol_gfx.h has been revisited: - - tighter validation checks on texture creation: - - content data validation now also happens in ```sg_make_image()``` (previously only in ```sg_update_image()```) - - validate that compressed textures are immutable - - separate "no data" validation checks for immutable vs dynamic/stream textures - - provided data size for creating or updating textures must match the expected surface sizes exactly - - fix PVRTC row and surface pitch computation according to the GL PVRTC extension spec - - better adhere to Metal documentation for the ```MTLTexture.replaceRegion``` parameters (when bytesPerImage is expected to be zero or not) - -- **02-Sep-2021**: some minor non-breaking additions: - - sokol_app.h: new events FOCUSED and UNFOCUSED to indicate that the - window has gained or lost the focused state (Win32: WM_SETFOCUS/WM_KILLFOCUS, - macOS: windowDidBecomeKey/windowDidResignKey, X11: FocusIn/FocusOut, - HTML5: focus/blur). - - sokol_app.h Emscripten backend: the input event keycode is now extracted - from the HTML5 code string which yields the actual unmapped virtual key code. - -- **21-Aug-2021**: some minor API tweaks in sokol_gl.h and sokol_debugtext.h, - one of them breaking (still minor though): - - sokol_gl.h has a new function ```sgl_default_context()``` which returns the - default context handle, it's the same as the global constant SGL_DEFAULT_CONTEXT, - but wrapping this in a function is better for language bindings - - ...and a similar function in sokol_debugtext.h: ```sdtx_default_context()``` - - The sokol_gl.h function ```sgl_default_pipeline()``` has been renamed to - ```sgl_load_default_pipeline()```. This fits better with the related - function ```sgl_load_pipeline()``` and doesn't 'semantically clash' - with the new function sgl_default_context(). The sgl_default_pipeline() - function is rarely used, so it's quite unlikely that this change breaks - your code. - -- **19-Aug-2021**: sokol_gl.h gained rendering context support, this allows - sokol-gl to render into different sokol-gfx render passes. No changes are - needed for existing sokol-gl code. Check the updated - [header documentation](https://github.com/floooh/sokol/blob/master/util/sokol_gl.h) - and the new sample - [sgl-context-sapp](https://floooh.github.io/sokol-html5/sgl-context-sapp.html) - for details! - -- **21-Jun-2021**: A new utility header sokol_color.h has been added, which adds - sokol_gfx.h-compatible named color constants and a handful initial utility - functions. See the [header documentation](https://github.com/floooh/sokol/blob/master/util/sokol_color.h) - for details. Many thanks to Stuart Adams (@nyalloc) for contributing the header! - -- **12-Apr-2021**: Minor new feature in sokol_app.h: mouse buttons are now - also reported as modifier flags in most input events (similar to the - Ctrl-, Alt-, Shift- and Super-key modifiers). This lets you quickly check - what mouse buttons are currently pressed in any input event without having - to keep track of pressed mouse buttons yourself. This is implemented in the following - sokol_app.h backends: Win32, UWP, Emscripten, X11 and macOS. Example - code is in the [events-sapp.cc](https://floooh.github.io/sokol-html5/events-sapp.html) sample - -- **10-Apr-2021**: followup fixes from yesterday: custom icon support on macOS - has been added (since macOS has no regular window icons, the dock icon is - updated instead), and a bugfix in the internal helper which select the - best matching candidate image (this actually always selected the first - candidate image) - -- **09-Apr-2021**: sokol_app.h now allows to programmatically set the window - icon in the Win32, X11 and HTML5 backends. Search for "WINDOW ICON SUPPORT" - in sokol_app.h for documentation, and see the new - [icon sample](https://floooh.github.io/sokol-html5/icon-sapp.html) for example code. - -- **01-Apr-2021**: some fixes in sokol_app.h's iOS backend: - - In the iOS Metal backend, high-dpi vs low-dpi works again. Some time - ago (around iOS 12.x) MTKView started to ignore the contentScaleFactor - property, which lead to sokol_app.h always setting up a HighDPI - framebuffer even when sapp_desc.high_dpi wasn't set. The fix is to set - the MTKView's drawableSize explicitly now. - - The iOS GL backend didn't support MSAA multisampling so far, this has - been fixed now, but only one MSAA mode (4x) is available, which will be - selected when sapp_desc.sample_count is greater than 1. - -- **31-Mar-2021**: sokol_audio.h on macOS no longer includes system framework - headers (AudioToolbox/AudioToolbox.h), instead the necessary declarations - are embedded directly in sokol_audio.h (to get the old behaviour and - force inclusion of AudioToolbox/AudioToolbox.h, define - ```SAUDIO_OSX_USE_SYSTEM_HEADERS``` before including the sokol_audio.h - implementation). This "fix" is both an experiment and an immediate workaround - for a current issue in Zig's HEAD version (what will eventually become - zig 0.8.0). See this issue for details: https://github.com/ziglang/zig/issues/8360). - The experiment is basically to see whether this approach generally makes sense - (replacing system headers with embedded declarations, so that the sokol headers - only depend on C standard library headers). This approach might - simplify cross-compilation and integration with other languages than C and C++. - -- **20-Mar-2021**: The Windows-specific OpenGL loader, and the platform-specific -GL header includes have been moved from sokol_app.h to sokol_gfx.h. This means: - - In general, the sokol_gfx.h implementation can now simply be included - without having to include other headers which provide the GL API declarations - first (e.g. when sokol_gfx.h is used without sokol_app.h, you don't need to - use a GL loader, or include the system-specific GL headers yourself). - - When sokol_gfx.h is used together with sokol_app.h, the include order - for the implementations doesn't matter anymore (until now, the sokol_app.h - implementation had to be included before the sokol_gfx.h implementation). - - The only "downside" (not really a downside) is that sokol_gfx.h now has - platform detection ifdefs to include the correct GL headers for a given - platform. Until now this problem was "delegated" to the library user. - - The old macro **SOKOL_WIN32_NO_GL_LOADER** has been removed, and replaced - with a more general **SOKOL_EXTERNAL_GL_LOADER**. Define this before - including the sokol_gfx.h implementation if you are using your own GL - loader or provide the GL API declarations in any other way. In this case, - sokol_gfx.h will not include any platform GL headers, and the embedded - Win32 GL loader will be disabled. - -- **22-Feb-2021**: Mouse input latency in sokol_app.h's macOS backend has been - quite significantly reduced, please see the detailed explanation [in this - PR](https://github.com/floooh/sokol/pull/483). Many thanks to @randrew for - the PR! - -- **19-Feb-2021**: sokol_app.h learned some Windows-specific config options -to redirect stdout/stderr to the parent terminal or a separate console -window, and allow outputting UTF-8 encoded text. For details, search for -"WINDOWS CONSOLE OUTPUT" in -[sokol_app.h](https://github.com/floooh/sokol/blob/master/sokol_app.h). Many -thanks to @garettbass for the initial PR! - -- **17-Feb-2021**: When compiled for iOS, the sokol_audio.h CoreAudio backend now -uses the **AVAudioSession** class to activate and deactivate audio output as needed. -This fixes sokol_audio.h for iPhones (so far, sokol_audio.h accidentally only worked -for iPads). Please see [this issue](https://github.com/floooh/sokol/issues/431) for details. -A somewhat unfortunate side effect of this fix is that sokol_audio.h must now be compiled -as Objective-C when targeting iOS, also note that a new framework must be linked: ```AVFoundation```. -Many thanks to @oviano for providing the PR! - -- **14-Feb-2021**: The Dear ImGui rendering backend in [sokol_imgui.h](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h) has been rewritten to only do a single -buffer-update per frame each for vertex- and index-data. This addresses performance-problems -with sg_append_buffer() in the GL backend on some platforms (see [this issue](https://github.com/floooh/sokol/issues/399) for details. - -- **13-Feb-2021**: A new utility header [sokol_nuklear.h](https://github.com/floooh/sokol/blob/master/util/sokol_nuklear.h) -has been added which implements a rendering backend for [Nuklear](https://github.com/Immediate-Mode-UI/Nuklear) -on top of sokol_gfx.h. Also see the new sample [nuklear-sapp](https://floooh.github.io/sokol-html5/nuklear-sapp.html). -Many thanks to **@wmerrifield** for the PR! - -- **10-Feb-2021**: The breaking API-update has been merged (mainly sokol_gfx.h). -Please see [this blogpost](https://floooh.github.io/2021/02/07/sokol-api-overhaul.html) -and the updates [sokol samples](https://floooh.github.io/sokol-html5/) for details. -I also created a git tag named 'pre-feb2021-api-changes' which captures the previous -state in all related projects. Please also update the [sokol-tools-bin](https://github.com/floooh/sokol-tools-bin) if you're using the sokol-shdc shader compiler. - -- **07-Feb-2021**: A PSA about upcoming breaking changes in (mainly) sokol_gfx.h: https://floooh.github.io/2021/02/07/sokol-api-overhaul.html - -- **20-Dec-2020**: A couple of minor breaking changes in the sokol_gfx.h and -sokol_app.h APIs as preparation for the upcoming automatic language binding -generation: - - in **sokol_gfx.h** nested unions have been removed: - - **sg_image_desc.depth/.layers** has been renamed to **.num_slices** - - **sg_attachment_desc.face/.layer/.slice** has been unified to **.slice** - - in **sokol_app.h** the return value of **sapp_run()** has been changed from - **int** to **void** (the function always returned zero anyway) - - Non-breaking (or at most potentially breaking) changes: - - expressions in enums have been replaced with integer literals (e.g. (1<<2) becomes 4) - - the value of **SAPP_MOUSEBUTTON_INVALID** has been changed from -1 to 0x100 - - For more information about the upcoming automatic language-bindings generation [see this bog post](https://floooh.github.io/2020/08/23/sokol-bindgen.html) - -- **02-Dec-2020**: sokol_gfx.h has a couple new public API functions for -destroying resources in two steps: - - sg_uninit_buffer + sg_dealloc_buffer - - sg_uninit_image + sg_dealloc_image - - sg_uninit_shader + sg_dealloc_shader - - sg_uninit_pipeline + sg_dealloc_pipeline - - sg_uninit_pass + sg_dealloc_pass - - Calling both functions in this order is identical with calling the - traditional sg_destroy_xxx() functions. See this PR for more details: - https://github.com/floooh/sokol/pull/435. Many thanks to @oviano for the - PR! - -- **28-Nov-2020**: In addition to the generic SOKOL_API_DECL and SOKOL_IMPL -defines there are now header-specific versions SOKOL_xxx_API_DECL and -SOKOL_xxx_IMPL (for instance SOKOL_GFX_API_DECL and SOKOL_GFX_IMPL). The -original motivation for splitting the SOKOL_API_DECL defines up is described -here: https://github.com/floooh/sokol/issues/428). The same change for -SOKOL_IMPL also finally unifies the approach used in the utility headers (in -the ```util``` subdirectory), which exclusively used the SOKOL_xxx_IMPL -pattern with the core headers which exclusively used SOKOL_IMPL before (all -headers accept both patterns now). Many thanks to @iboB for providing the -API_DECL PR! - -- **17-Nov-2020**: A new utility header **sokol_shape.h** to generate - vertices+indices for simple shapes (plane, box, sphere, cylinder and torus), - which seamlessly plug into the sokol_gfx.h resource creation functions. As - with most new utility headers, the initial functionality is a bit bare bones - and the public API shouldn't be considered stable yet. Check the sokol-samples - webpage for new and updates samples: https://floooh.github.io/sokol-html5/ - -- **08-Nov-2020** PSA: It appears that RenderDoc v1.10 chokes on the new - D3D11/DXGI swapchain code from 10-Oct-2020 in sokol_app.h. The current - RenderDoc Nightly Build works, so I guess in v1.11 everything will be fine. - -- **03-Nov-2020**: sokol_app.h: the missing drag'n'drop support for HTML5/WASM - has been added. This adds two platform-specific functions - ```sapp_html5_get_dropped_file_size()``` and - ```sapp_html5_fetch_dropped_file()```. Please read the documentation - section in sokol_app.h under 'DRAG AND DROP SUPPORT' for additional - details and example code. Also consult the source code of the new - ```droptest-sapp``` sample for an example of how to load the content - of dropped files on the web and native platforms: - - https://floooh.github.io/sokol-html5/droptest-sapp.html - - -- **27-Oct-2020**: I committed a bugfix for a longstanding WebGL canvas id versus - css-selector confusion in the emscripten/WASM backend code in sokol_app.h. - I think the fix should not require any changes in your code (because if - you'd be using a canvas name different from the default "canvas" it wouldn't - have worked before anyway). See this bug for details: https://github.com/floooh/sokol/issues/407 - -- **22-Oct-2020**: sokol_app.h now has file drag'n'drop support on Win32, - macOS and Linux. WASM/HTML5 support will be added soon-ish. This will - work a bit differently because of security-related restrictions in the - HTML5 drag'n'drop API, but more on that later. For documentation, - search for 'DRAG AND DROP SUPPORT' in [sokol_app.h](https://github.com/floooh/sokol/blob/master/sokol_app.h). - - Check out [events-sapp.c](https://github.com/floooh/sokol-samples/blob/master/sapp/events-sapp.cc) - for a simple usage example (I will also add a more real-world example to my - chips emulators once the WASM/HTML5 implementation is ready). - - Many thanks for @prime31 and @hb3p8 for the initial PRs and valuable feature - discussions! - -- **10-Oct-2020**: Improvements to the sokol_app.h Win32+D3D11 and UWP+D3D11 swapchain code: - - In the Win32+D3D11 backend and when running on Win10, - ```DXGI_SWAP_EFFECT_FLIP_DISCARD``` is now used. This gets rid of a - deprecation warning in the debugger console and also should allow slightly - more efficient swaps in some situations. When running on Win7 or Win8, the - traditional ```DXGI_SWAP_EFFECT_DISCARD``` is used. - - The UWP backend now supports MSAA multisampling (the required fixes for - this are the same as in the Win32 backend with the new swap effect: a - separate MSAA texture and render-target-view is created where - rendering goes into, and this MSAA texture is resolved into the actual - swapchain surface before presentation). - -- **07-Oct-2020**: - A fix in the ALSA/Linux backend initialization in sokol_audio.h: Previously, - initialization would fail if ALSA can't allocate the exact requested - buffer size. Instead sokol_audio.h let's now pick ALSA a suitable buffer - size. Also better log messages in the ALSA initialization code if something - goes wrong. Unfortunately I'm not able to reproduce the buffer allocation - problem on my Linux machine. Details are in this issue: https://github.com/floooh/sokol/issues/400 - - **NARRATOR**: the fix didn't work. - -- **02-Oct-2020**: - The sokol_app.h Win32 backend can now render while moving and resizing - the window. NOTE that resizing the swapchain buffers (and receiving - SAPP_EVENTTYPE_RESIZED events) is deferred until the resizing finished. - Resizing the swapchain buffers each frame created a substantial temporary - memory spike of up to several hundred MBytes. I need to figure out a better - swapchain resizing strategy. - -- **30-Sep-2020**: - sokol_audio.h now works on UWP, thanks again to Alberto Fustinoni - (@albertofustinoni) for the PR! - -- **26-Sep-2020**: - sokol_app.h gained a new function sapp_set_window_title() to change - the window title on Windows, macOS and Linux. Many thanks to - @medvednikov for the initial PR! - -- **23-Sep-2020**: - sokol_app.h now has initial UWP support using the C++/WinRT set of APIs. - Currently this requires "bleeding edge" tools: A recent VS2019 version, - and a very recent Windows SDK version (at least version 10.0.19041.0). - Furthermore the sokol_app.h implementation must be compiled as C++17 - (this is a requirement of the C++/WinRT headers). Note that the Win32 - backend will remain the primary and recommended backend on Windows. The UWP - backend should only be used when the Win32 backend is not an option. - The [sokol-samples](https://github.com/floooh/sokol-samples) project - has two new build configs ```sapp-uwp-vstudio-debug``` and - ```sapp-uwp-vstudio-release``` to build the sokol-app samples for UWP. - - Many thanks to Alberto Fustinoni (@albertofustinoni) for providing - the initial PR! - - (also NOTE: UWP-related fixes in other sokol headers will follow) - -- **22-Sep-2020**: - A small fix in sokol_app.h's Win32 backend: when a mouse button is pressed, - mouse input is now 'captured' by calling SetCapture(), and when the last - mouse button is released, ReleaseCapture() is called. This also provides - mouse events outside the window area as long as a mouse button is pressed, - which is useful for windowed UI applicactions (this is not the same as the - more 'rigorous' and explicit pointer-lock feature which is more useful for - camera-controls) - -- **31-Aug-2020**: - Internal change: The D3D11/DXGI backend code in sokol_gfx.h and sokol_app.h - now use the D3D11 and DXGI C++-APIs when the implementation is compiled as - C++, and the C-APIs when the implementation is compiled as C (before, the C - API was also used when the implementation is compiled as C++). The new - behaviour is useful when another header *must* use the D3D11/DXGI C++ APIs - but should be included in the same compilation unit as sokol_gfx.h an - sokol_app.h (for example see this PR: - https://github.com/floooh/sokol/pull/351). - -- **24-Aug-2020**: - The backend-specific callback functions that are provided to sokol_gfx.h - in the ```sg_setup()``` initialization call now have alternative - versions which accept a userdata-pointer argument. The userdata-free functions - still exist, so no changes are required for existing code. - -- **02-Aug-2020**: - - sokol_app.h now has a mouse-lock feature (aka pointer-lock) via two - new functions ```void sapp_lock_mouse(bool lock)``` and ```bool sapp_mouse_locked(void)```. - For documentation, please search for 'MOUSE LOCK' in sokol_app.h. - The sokol-app samples [events-sapp](https://floooh.github.io/sokol-html5/events-sapp.html) - and [cgltf-sapp](https://floooh.github.io/sokol-html5/cgltf-sapp.html) have been - updated to demonstrate the feature. - - sokol_app.h Linux: mouse pointer visibility (via ```void sapp_show_mouse(bool show)```) - has been implemented for Linux/X11 - - sokol_app.h WASM: mouse wheel scroll deltas are now 'normalized' between - the different scroll modes (pixels, lines, pages). See this issue: - https://github.com/floooh/sokol/issues/339. Many thanks to @bqqbarbhg for - investigating the issue and providing a solution! - - sokol_app.h now has [better documentation](https://github.com/floooh/sokol/blob/89a3bb8da0a2df843d6cc60a270ddc69f9aa69d6/sokol_app.h#L70) - what system libraries must be linked on the various platforms (and on Linux two additional libraries must be - linked now: Xcursor and Xi) - -- **22-Jul-2020**: **PLEASE NOTE** cmake 3.18 breaks some of sokol samples when - compiling with the Visual Studio toolchain because some C files now actually - compile as C++ for some reason (see: - https://twitter.com/FlohOfWoe/status/1285996526117040128). Until this is - fixed, or I have come up with a workaround, please use an older cmake version - to build the sokol samples with the Visual Studio compiler. - - (Update: I have added a workaround to fips: https://github.com/floooh/fips/commit/89997b8ebdca6fc9455a5cfe6145eecaa017df49 - which fixes the issue at least for fips projects) - -- **14-Jul-2020**: - - sapp_mouse_shown() has been implemented for macOS (thanks to @slmjkdbtl for - providing the initial PR!) - - On macOS, the lower-level functions CGDisplayShowCursor and CGDisplayHideCursor - are now used instead of the NSCursor class. This is in preparation for the - 'pointer lock' feature which will also use CGDisplay* functions. - - Calling ```sapp_show_mouse(bool visible)``` no longer 'stacks' (e.g. there's - no 'hidden counter' underneath anymore, instead calling ```sapp_show_mouse(true)``` - will always show the cursor and ```sapp_show_mouse(false)``` will always - hide it. This is a different behaviour than the underlying Win32 and - macOS functions ShowCursor() and CGDisplaShow/HideCursor() - - The mouse show/hide behaviour can now be tested in the ```events-sapp``` sample - (so far this only works on Windows and macOS). - -- **13-Jul-2020**: - - On macOS and iOS, sokol_app.h and sokol_gfx.h can now be compiled with - ARC (Automatic Reference Counting) **disabled** (previously ARC had to be - enabled). - - Compiling with ARC enabled is still supported but with a little caveat: - if you're compiling sokol_app.h or sokol_gfx.h in ObjC mode (not ObjC++ - mode) *AND* ARC is enabled, then the Xcode version must be more recent - than before (the language feature ```__has_feature(objc_arc_fields)``` - must be supported, which I think has been added in Xcode 10.2, I couldn't - find this mentioned in any Xcode release notes though). Compiling with - ARC disabled should also work on older Xcode versions though. - - Various internal code cleanup things: - - sokol_app.h had the same 'structural cleanup' as sokol_gfx.h in - January, all internal state (including ObjC id's) has been merged into - a single big state structure. Backend specific struct declarations - have been moved closer together in the header, and - backend-specific structures and functions have been named more - consistently for better 'searchability' - - The 'mini GL' loader in the sokol_app.h Win32+WGL backend has been - rewritten to use X-Macros (less redundant lines of code) - - All macOS and iOS code has been revised and cleaned up - - On macOS a workaround for a (what looks like) post-Catalina - NSOpenGLView issue has been added: if the sokol_app.h window doesn't - fit on screen (and was thus 'clamped' by Cocoa) *AND* the - content-size was not set to native Retina resolution, the initial - content size was reported as if it was in Retina resolution. This - caused an empty screen to be rendered in the imgui-sapp demo. The - workaround is to hook into the NSOpenGLView reshape event at which - point the reported content size is correct. - - On macOS and iOS, the various 'view delegate' objects have been - removed, and rendering happens instead in the subclasses of MTKView, - GLKView and NSOpenGLView. - - On macOS and iOS, there's now proper cleanup code in the - applicationWillTerminate callback (although note that on iOS this - function isn't guaranteed to be called, because an application can - also simply be killed by the operating system. - -- **22-Jun-2020**: The X11/GLX backend in sokol_app.h now has (soft-)fullscreen -support, bringing the feature on par with Windows and macOS. Many thanks to -@medvednikov for the PR! - -- **20-Jun-2020**: Some work to better support older DX10-level GPUs in the -sokol_gfx.h D3D11 backend: - - sg_make_shader() now by default compiles HLSL shader code as shader model 4.0 - (previously shader model 5.0 which caused problems with some older - Intel GPUs still in use, see this issue: https://github.com/floooh/sokol/issues/179) - - A new string item ```const char* d3d11_target``` in ```sg_shader_stage_desc``` now allows - to pass in the D3D shader model for compiling shaders. This defaults to - "vs_4_0" for the vertex shader stage and "ps_4_0" for the fragment shader stage. - The minimal DX shader model for use with the sokol_gfx.h D3D11 backend is - shader model 4.0, because that's the first shader model supporting - constant buffers. - - The *sokol-shdc* shader compiler tool has a new output option ```hlsl4``` - to generate HLSL4 source code and shader model 4.0 byte code. - - All embedded D3D shader byte code in the sokol utility headers has been - changed from shader model 5.0 to 4.0 - - If you are using sokol_gfx.h with sokol-shdc, please update both at the same time - to avoid compilation errors caused by the new ```sg_shader_stage_desc.d3d11_target``` - item. The sg_shader_desc initialization code in sokol-shdc has now been made more - robust to prevent similar problems in the future. - -- **14-Jun-2020**: I have added a very simple utility header ```sokol_memtrack.h``` -which allows to track memory allocations in sokol headers (number and overall -size of allocations) by overriding the macros SOKOL_MALLOC, SOKOL_CALLOC and -SOKOL_FREE. Simply include ```sokol_memtrack.h``` before the other sokol -header implementation includes to enable memory tracking in those headers -(but remember that the sokol_memtrack.h implementation must only be included -once in the whole project, so this only works when all other sokol header -implementations are included in the same compilation unit). - -- **06-Jun-2020**: Some optimizations in the sokol_gfx.h GL backend to avoid - redundant GL calls in two areas: in the sg_begin_pass() calls when not - clearing the color- and depth-stencil-attachments, and in sg_apply_bindings() - when binding textures. Everything should behave exactly as before, but if - you notice any problems in those areas, please file a bug. Many thanks to - @edubart for the PRs! - -- **01-Jun-2020**: sokol_app.h now allows to toggle to and from fullscreen -programmatically and to query the current fullscreen state via 2 new -functions: ```sapp_toggle_fullscreen()``` and ```sapp_is_fullscreen()```. -Currently this is only implemented for Windows and macOS (not Linux). -Thanks to @mattiasljungstrom for getting the feature started and providing -the Win32 implementation! - -- **28-May-2020**: a small quality-of-life improvement for C++ coders: when the -sokol headers are included into C++, all public API functions which take a -pointer to a struct now have a C++ overload which instead takes a const-ref. -This allows to move the struct initialization right into the function call -just like in C99. For instance, in C99 one can write: - ```c - sg_buffer buf = sg_make_buffer(&(sg_buffer_desc){ - .size = sizeof(vertices), - .type = SG_BUFFERTYPE_VERTEXBUFFER, - .content = vertices - }); - ``` - In C++ it isn't possible to take the address of an 'adhoc-initialized' - struct like this, but with the new reference-wrapper functions (and C++20 - designated initialization) this should work now: - ```cpp - sg_buffer buf = sg_make_buffer({ - .size = sizeof(vertices), - .type = SG_BUFFERTYPE_VERTEXBUFFER, - .content = vertices - }); - ``` - Many thanks to @garettbass for providing the PR! - - -- **27-May-2020**: a new utility header [sokol_debugtext.h](https://github.com/floooh/sokol/blob/master/util/sokol_debugtext.h) -for rendering simple ASCII text using vintage home computer fonts via sokol_gfx.h - -- **13-May-2020**: a new function in sokol_time.h to round a measured frame time -to common display refresh rates: ```stm_round_to_common_refresh_rate()```. -See the header documentation for the motivation behind this function. - -- **02-May-2020**: sokol_app.h: the 'programmatic quit' behaviour on the -web-platform is now more in line with other platforms: calling -```sapp_quit()``` will invoke the cleanup callback function, perform -platform-specific cleanup (like unregistering JS event handlers), and finally -exit the frame loop. In typical scenarios this isn't very useful (because -usually the user will simply close the tab, which doesn't allow to run -cleanup code), but it's useful for situations where the same -code needs to run repeatedly on a web page. Many thanks to @caiiiycuk -for providing the PR! - -- **30-Apr-2020**: experimental WebGPU backend and a minor breaking change: - - sokol_gfx.h: a new WebGPU backend, expect frequent breakage for a while - because the WebGPU API is still in flux - - a new header sokol_glue.h, with interop helper functions when specific combinations - of sokol headers are used together - - changes in the way sokol_gfx.h is initialized via a new layout of the - sg_desc structure - - sokol_gfx.h: a new ```sg_sampler_type``` enum which is required for - shader creation to tell the WebGPU backend about the sampler data types - (float, signed int, or unsigned int) used in the shader - - sokol_app.h: a handful new functions to query default framebuffer attributes (color- and - depth-buffer pixel formats, and MSAA sample count) - - sokol_app.h: WebGPU device and swapchain initialization (currently only - in the emscripten code path) - - [sokol-shdc](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md) has - been updated with WebGPU support (currently outputs SPIRV bytecode), and to output the new - ```sg_sampler_type``` enum in ```sg_shader_image_desc``` - - [sokol-samples](https://github.com/floooh/sokol-samples/) has a new set of - backend-specific WebGPU samples, and the other samples have been updated - for the new sokol-gfx initialization - - ```pre-webgpu``` tags have been added to the [sokol](https://github.com/floooh/sokol/releases/tag/pre-webgpu), [sokol-samples](https://github.com/floooh/sokol-samples/releases/tag/pre-webgpu), [sokol-tools](https://github.com/floooh/sokol-tools/releases/tag/pre-webgpu) - and [sokol-tools-bin](https://github.com/floooh/sokol-tools-bin/releases/tag/pre-webgpu) github repositories (in case you need to continue working with - the older versions) - - please see this [blog post](https://floooh.github.io/2020/04/26/sokol-spring-2020-update.html) - for more details - -- **05-Apr-2020**: A bugfix in sokol_gl.h, the (fairly recent) optimization for - merging draw calls contained a bug that could be triggered in an "empty" - sgl_begin/sgl_end pair (with no vertices recorded inbetween). This could - lead to the following draw call being rendered with the wrong uniform data. - -- **30-Jan-2020**: Some cleanup in sokol_gfx.h in the backend implementation code, - internal data structures and documentation comments. The public - API hasn't changed, so the change should be completely invisible - from the outside. - -- **02-Dec-2019**: Initial clipboard support in sokol_app.h for Windows, macOS - and HTML5. This allows to read and write UTF-8 encoded strings from and - to the target platform's shared clipboard. - - A 'real-world' example usage is in the [Visual6502 Remix project](https://github.com/floooh/v6502r). - - Unfortunately clipboard support on the HTML5 platform comes with a lot of - platform-specific caveats which can't be solved in sokol_app.h alone - because of the restrictions the web platform puts on clipboard access and - different behaviours and support levels of the various HTML5 clipboard - APIs. I'm not really happy with the current HTML5 clipboard - implementation. It sorta works, but it sure ain't pretty :) - - Maybe the situation will improve in a few years when all browsers agree - on and support the new [permission-based clipboard - API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API). - - For documentation of the clipboard feature, search for CLIPBOARD SUPPORT - in sokol_app.h - -- **08-Sep-2019**: sokol_gfx.h now supports clamp-to-border texture sampling: - - the enum ```sg_wrap``` has a new member ```SG_WRAP_CLAMP_TO_BORDER``` - - there's a new enum ```sg_border_color``` - - the struct ```sg_image_desc``` has a new member ```sg_border_color border_color``` - - new feature flag in ```sg_features```: ```image_clamp_to_border``` - - Note the following caveats: - - - clamp-to-border is only supported on a subset of platforms, support can - be checked at runtime via ```sg_query_features().image_clamp_to_border``` - (D3D11, desktop-GL and macOS-Metal support clamp-to-border, - all other platforms don't) - - there are three hardwired border colors: transparent-black, - opaque-black and opaque-white (modern 3D APIs have moved away from - a freely programmable border color) - - if clamp-to-border is not supported, sampling will fall back to - clamp-to-edge without a validation warning - - Many thanks to @martincohen for suggesting the feature and providing the initial -D3D11 implementation! - -- **31-Aug-2019**: The header **sokol_gfx_cimgui.h** has been merged into -[**sokol_gfx_imgui.h**](https://github.com/floooh/sokol/blob/master/util/sokol_gfx_imgui.h). -Same idea as merging sokol_cimgui.h into sokol_imgui.h, the implementation -is now "bilingual", and can either be included into a C++ file or into a C file. -When included into a C++ file, the Dear ImGui C++ API will be called directly, -otherwise the C API bindings via cimgui.h - -- **28-Aug-2019**: The header **sokol_cimgui.h** has been merged into -[**sokol_imgui.h**](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h). -The sokol_cimgui.h header had been created to implement Dear ImGui UIs from -pure C applications, instead of having to fall back to C++ just for the UI -code. However, there was a lot of code duplication between sokol_imgui.h and -sokol_cimgui.h, so that it made more sense to merge the two headers. The C vs -C++ code path will be selected automatically: When the implementation of -sokol_imgui.h is included into a C++ source file, the Dear ImGui C++ API will -be used. Otherwise, when the implementation is included into a C source file, -the C API via cimgui.h - -- **27-Aug-2019**: [**sokol_audio.h**](https://github.com/floooh/sokol/blob/master/sokol_audio.h) - now has an OpenSLES backend for Android. Many thanks to Sepehr Taghdisian (@septag) - for the PR! - -- **26-Aug-2019**: new utility header for text rendering, and fixes in sokol_gl.h: - - a new utility header [**sokol_fontstash.h**](https://github.com/floooh/sokol/blob/master/util/sokol_fontstash.h) - which implements a renderer for [fontstash.h](https://github.com/memononen/fontstash) - on top of sokol_gl.h - - **sokol_gl.h** updates: - - Optimization: If no relevant state between two begin/end pairs has - changed, draw commands will be merged into a single sokol-gfx draw - call. This is especially useful for text- and sprite-rendering (previously, - each begin/end pair would always result in one draw call). - - Bugfix: When calling sgl_disable_texture() the previously active - texture would still remain active which could lead to rendering - artefacts. This has been fixed. - - Feature: It's now possible to provide a custom shader in the - 'desc' argument of *sgl_make_pipeline()*, as long as the shader - is "compatible" with sokol_gl.h, see the sokol_fontstash.h - header for an example. This feature isn't "advertised" in the - sokol_gl.h documentation because it's a bit brittle (for instance - if sokol_gl.h updates uniform block structures, custom shaders - would break), but it may still come in handy in some situations. - -- **20-Aug-2019**: sokol_gfx.h has a couple new query functions to inspect the - default values of resource-creation desc structures: - - ```c - sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc); - sg_image_desc sg_query_image_defaults(const sg_image_desc* desc); - sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc); - sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc); - sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc); - ``` - These functions take a pointer to a resource creation desc struct that - may contain zero-initialized values (to indicate default values) and - return a new struct where the zero-init values have been replaced with - concrete values. This is useful to inspect the actual creation attributes - of a resource. - -- **18-Aug-2019**: - - Pixelformat and runtime capabilities modernization in sokol_gfx.h (breaking changes): - - The list of pixel formats supported in sokol_gfx.h has been modernized, - many new formats are available, and some formats have been removed. The - supported pixel formats are now identical with what WebGPU provides, - minus the SRGB formats (if SRGB conversion is needed it should be done - in the pixel shader) - - The pixel format list is now more "orthogonal": - - one, two or four color components (R, RG, RGBA) - - 8-, 16- or 32-bit component width - - unsigned-normalized (no postfix), signed-normalized (SN postfix), - unsigned-integer (UI postfix) and signed-integer (SI postfix) - and float (F postfix) component types. - - special pixel formats BGRA8 (default render target format on - Metal and D3D11), RGB10A2 and RG11B10F - - DXT compressed formats replaced with BC1 to BC7 (BC1 to BC3 - are identical to the old DXT pixel formats) - - packed 16-bit formats (like RGBA4) have been removed - - packed 24-bit formats (RGB8) have been removed - - Use the new function ```sg_query_pixelformat()``` to get detailed - runtime capability information about a pixelformat (for instance - whether it is supported at all, can be used as render target etc...). - - Use the new function ```sg_query_limits()``` to query "numeric limits" - like maximum texture dimensions for different texture types. - - The enumeration ```sg_feature``` and the function ```sg_query_feature()``` - has been replaced with the new function ```sg_query_features()```, which - returns a struct ```sg_features``` (this contains a bool for each - optional feature). - - The default pixelformat for render target images and pipeline objects - now depends on the backend: - - for GL backends, the default pixelformat stays the same: RGBA8 - - for the Metal and D3D11 backends, the default pixelformat for - render target images is now BGRA8 (the reason is because - MTKView's pixelformat was always BGRA8 but this was "hidden" - through an internal hack, and a BGRA swapchain is more efficient - than RGBA in D3D11/DXGI) - - Because of the above RGBA/BGRA change, you may see pixelformat validation - errors in existing code if the code assumes that a render target image is - always created with a default pixelformat of RGBA8. - - Changes in sokol_app.h: - - The D3D11 backend now creates the DXGI swapchain with BGRA8 pixelformat - (previously: RGBA8), this allows more efficient presentation in some - situations since no format-conversion-blit needs to happen. - -- **18-Jul-2019**: - - sokol_fetch.h has been fixed and can be used again :) - -- **11-Jul-2019**: - - Don't use sokol_fetch.h for now, the current version assumes that - it is possible to obtain the content size of a file from the - HTTP server without downloading the entire file first. Turns out - that's not possible with vanilla HTTP when the web server serves - files compressed (in that case the Content-Length is the _compressed_ - size, yet JS/WASM only has access to the uncompressed data). - Long story short, I need to go back to the drawing board :) - -- **06-Jul-2019**: - - new header [sokol_fetch.h](https://github.com/floooh/sokol/blob/master/sokol_fetch.h) for asynchronously loading data. - - make sure to carefully read the embedded documentation - for making the best use of the header - - two new samples: [simple PNG file loadng with stb_image.h](https://floooh.github.io/sokol-html5/loadpng-sapp.html) and [MPEG1 streaming with pl_mpeg.h](https://floooh.github.io/sokol-html5/plmpeg-sapp.html) - - sokol_gfx.h: increased SG_MAX_SHADERSTAGE_BUFFERS configuration - constant from 4 to 8. - -- **10-Jun-2019**: sokol_app.h now has proper "application quit handling": - - a pending quit can be intercepted, for instance to show a "Really Quit?" dialog box - - application code can now initiate a "soft quit" (interceptable) or - "hard quit" (not interceptable) - - on the web platform, the standard "Leave Site?" dialog box implemented - by browsers can be shown when the user leaves the site - - Android and iOS currently don't have any of those features (since the - operating system may decide to terminate mobile applications at any time - anyway, if similar features are added they will most likely have - similar limitations as the web platform) - For details, search for 'APPLICATION QUIT' in the sokol_app.h documentation - header: https://github.com/floooh/sokol/blob/master/sokol_app.h - - The [imgui-highdpi-sapp](https://github.com/floooh/sokol-samples/tree/master/sapp) - contains sample code for all new quit-related features. - -- **08-Jun-2019**: some new stuff in sokol_app.h: - - the ```sapp_event``` struct has a new field ```bool key_repeat``` - which is true when a keyboard event is a key-repeat (for the - event types ```SAPP_EVENTTYPE_KEY_DOWN``` and ```SAPP_EVENTTYPE_CHAR```). - Many thanks to [Scott Lembcke](https://github.com/slembcke) for - the pull request! - - a new function to poll the internal frame counter: - ```uint64_t sapp_frame_count(void)```, previously the frame counter - was only available via ```sapp_event```. - - also check out the new [event-inspector sample](https://floooh.github.io/sokol-html5/wasm/events-sapp.html) - -- **04-Jun-2019**: All sokol headers now recognize a config-define ```SOKOL_DLL``` - if sokol should be compiled into a DLL (when used with ```SOKOL_IMPL```) - or used as a DLL. On Windows, this will prepend the public function declarations - with ```__declspec(dllexport)``` or ```__declspec(dllimport)```. - -- **31-May-2019**: if you're working with emscripten and fips, please note the - following changes: - - https://github.com/floooh/fips#public-service-announcements - -- **27-May-2019**: some D3D11 updates: - - The shader-cross-compiler can now generate D3D bytecode when - running on Windows, see the [sokol-shdc docs](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md) for more -details. - - sokol_gfx.h no longer needs to be compiled with a - SOKOL_D3D11_SHADER_COMPILER define to enable shader compilation in the - D3D11 backend. Instead, the D3D shader compiler DLL (d3dcompiler_47.dll) - will be loaded on-demand when the first HLSL shader needs to be compiled. - If an application only uses D3D shader byte code, the compiler DLL won't - be loaded into the process. - -- **24-May-2019** The shader-cross-compiler can now generate Metal byte code -for macOS or iOS when the build is running on macOS. This is enabled -automatically with the fips-integration files in [sokol-tools-bin](https://github.com/floooh/sokol-tools-bin), -see the [sokol-shdc docs](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md) for more -details. - -- **16-May-2019** two new utility headers: *sokol_cimgui.h* and *sokol_gfx_cimgui.h*, -those are the same as their counterparts sokol_imgui.h and sokol_gfx_imgui.h, but -use the [cimgui](https://github.com/cimgui/cimgui) C-API for Dear ImGui. This -is useful if you don't want to - or cannot - use C++ for creating Dear ImGui UIs. - - Many thanks to @prime31 for contributing those! - - sokol_cimgui.h [is used -here](https://floooh.github.io/sokol-html5/wasm/cimgui-sapp.html), and -sokol_gfx_cimgui.h is used for the [debugging UI -here](https://floooh.github.io/sokol-html5/wasm/sgl-microui-sapp-ui.html) - -- **15-May-2019** there's now an optional shader-cross-compiler solution for -sokol_gfx.h: [see here for details](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md). -This is "V1.0" with two notable features missing: - - - an include-file feature for GLSL shaders - - compilation to Metal- and D3D-bytecode (currently - only source-code generation is supported) - - The [sokol-app samples](https://floooh.github.io/sokol-html5/) have been - ported to the new shader-cross-compilation, follow the ```src``` and - ```glsl``` links on the specific sample webpages to see the C- and GLSL- - source-code. - -- **02-May-2019** sokol_gfx.h has a new function ```sg_query_backend()```, this -will return an enum ```sg_backend``` identifying the backend sokol-gfx is -currently running on, which is one of the following values: - - - SG_BACKEND_GLCORE33 - - SG_BACKEND_GLES2 - - SG_BACKEND_GLES3 - - SG_BACKEND_D3D11 - - SG_BACKEND_METAL_MACOS - - SG_BACKEND_METAL_IOS - - When compiled with SOKOL_GLES3, sg_query_backend() may return SG_BACKEND_GLES2 - when the runtime platform doesn't support GLES3/WebGL2 and had to fallback - to GLES2/WebGL2. - - When compiled with SOKOL_METAL, sg_query_backend() will return SG_BACKEND_METAL_MACOS - when the compile target is macOS, and SG_BACKEND_METAL_IOS when the target is iOS. - -- **26-Apr-2019** Small but breaking change in **sokol_gfx.h** how the vertex -layout definition in sg_pipeline_desc works: - - Vertex component names and semantics (needed by the GLES2 and D3D11 backends) have moved from ```sg_pipeline_desc``` into ```sg_shader_desc```. - - This may seem like a rather pointless small detail to change, especially - for breaking existing code, but the whole thing will make a bit more - sense when the new shader-cross-compiler will be integrated which I'm - currently working on (here: https://github.com/floooh/sokol-tools). - - While working on getting reflection data out of the shaders (e.g. what - uniform blocks and textures the shader uses), it occurred to me that - vertex-attribute-names and -semantics are actually part of the reflection - info and belong to the shader, not to the vertex layout in the pipeline - object (which only describes how the incoming vertex data maps to - vertex-component **slots**. Instead of (optionally) mapping this - association through a name, the pipeline's vertex layout is now always - strictly defined in terms of numeric 'bind slots' for **all** sokol_gfx.h - backends. For 3D APIs where the vertex component slot isn't explicitly - defined in the shader language (GLES2/WebGL, D3D11, and optionally - GLES3/GL), the shader merely offers a lookup table how vertex-layout - slot-indices map to names/semantics (and the underlying 3D API than maps - those names back to slot indices, which shows that Metal and GL made the - right choice defining the slots right in the shader). - - Here's how the code changes (taken from the triangle-sapp.c sample): - - **OLD**: - ```c - /* create a shader */ - sg_shader shd = sg_make_shader(&(sg_shader_desc){ - .vs.source = vs_src, - .fs.source = fs_src, - }); - - /* create a pipeline object (default render states are fine for triangle) */ - pip = sg_make_pipeline(&(sg_pipeline_desc){ - /* if the vertex layout doesn't have gaps, don't need to provide strides and offsets */ - .shader = shd, - .layout = { - .attrs = { - [0] = { .name="position", .sem_name="POS", .format=SG_VERTEXFORMAT_FLOAT3 }, - [1] = { .name="color0", .sem_name="COLOR", .format=SG_VERTEXFORMAT_FLOAT4 } - } - }, - }); - ``` - - **NEW**: - ```c - /* create a shader */ - sg_shader shd = sg_make_shader(&(sg_shader_desc){ - .attrs = { - [0] = { .name="position", .sem_name="POS" }, - [1] = { .name="color0", .sem_name="COLOR" } - }, - .vs.source = vs_src, - .fs.source = fs_src, - }); - - /* create a pipeline object (default render states are fine for triangle) */ - pip = sg_make_pipeline(&(sg_pipeline_desc){ - /* if the vertex layout doesn't have gaps, don't need to provide strides and offsets */ - .shader = shd, - .layout = { - .attrs = { - [0].format=SG_VERTEXFORMAT_FLOAT3, - [1].format=SG_VERTEXFORMAT_FLOAT4 - } - }, - }); - ``` - - ```sg_shader_desc``` has a new embedded struct ```attrs``` which - contains a vertex attribute _name_ (for GLES2/WebGL) and - _sem_name/sem_index_ (for D3D11). For the Metal backend this struct is - ignored completely, and for GLES3/GL it is optional, and not required - when the vertex shader inputs are annotated with ```layout(location=N)```. - - The remaining attribute description members in ```sg_pipeline_desc``` are: - - **.format**: the format of input vertex data (this can be different - from the vertex shader's inputs when data is extended during - vertex fetch (e.g. input can be vec3 while the vertex shader - expects vec4) - - **.offset**: optional offset of the vertex component data (not needed - when the input vertex has no gaps between the components) - - **.buffer**: the vertex buffer bind slot if the vertex data is coming - from different buffers - - Also check out the various samples: - - - for GLSL (explicit slots via ```layout(location=N)```): https://github.com/floooh/sokol-samples/tree/master/glfw - - for D3D11 (semantic names/indices): https://github.com/floooh/sokol-samples/tree/master/d3d11 - - for GLES2: (vertex attribute names): https://github.com/floooh/sokol-samples/tree/master/html5 - - for Metal: (explicit slots): https://github.com/floooh/sokol-samples/tree/master/metal - - ...and all of the above combined: https://github.com/floooh/sokol-samples/tree/master/sapp - -- **19-Apr-2019** I have replaced the rather inflexible render-state handling -in **sokol_gl.h** with a *pipeline stack* (like the GL matrix stack, but with -pipeline-state-objects), along with a couple of other minor API tweaks. - - These are the new pipeline-stack functions: - ```c - sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc); - void sgl_destroy_pipeline(sgl_pipeline pip); - void sgl_default_pipeline(void); - void sgl_load_pipeline(sgl_pipeline pip); - void sgl_push_pipeline(void); - void sgl_pop_pipeline(void); - ``` - - A pipeline object is created just like in sokol_gfx.h, but without shaders, - vertex layout, pixel formats, primitive-type and sample count (these details - are filled in by the ```sgl_make_pipeline()``` wrapper function. For instance - to create a pipeline object for additive transparency: - - ```c - sgl_pipeline additive_pip = sgl_make_pipeline(&(sg_pipeline_desc){ - .blend = { - .enabled = true, - .src_factor_rgb = SG_BLENDFACTOR_ONE, - .dst_factor_rgb = SG_BLENDFACTOR_ONE - } - }); - ``` - - And to render with this, simply call ```sgl_load_pipeline()```: - - ```c - sgl_load_pipeline(additive_pip); - sgl_begin_triangles(); - ... - sgl_end(); - ``` - - Or to preserve and restore the previously active pipeline state: - - ```c - sgl_push_pipeline(); - sgl_load_pipeline(additive_pip); - sgl_begin_quads(); - ... - sgl_end(); - sgl_pop_pipeline(); - ``` - - You can also load the 'default pipeline' explicitly on the top of the - pipeline stack with ```sgl_default_pipeline()```. - - The other API change is: - - - ```sgl_state_texture(bool b)``` has been replaced with ```sgl_enable_texture()``` - and ```sgl_disable_texture()``` - - The code samples have been updated accordingly: - - - [sgl-sapp.c](https://github.com/floooh/sokol-samples/blob/master/sapp/sgl-sapp.c) - - [sgl-lines-sapp.c](https://github.com/floooh/sokol-samples/blob/master/sapp/sgl-lines-sapp.c) - - [sgl-microui-sapp.c](https://github.com/floooh/sokol-samples/blob/master/sapp/sgl-microui-sapp.c) - -- **01-Apr-2019** (not an April Fool's joke): There's a new **sokol_gl.h** -util header which implements an 'OpenGL-1.x-in-spirit' rendering API on top -of sokol_gfx.h (vertex specification via begin/end, and a matrix stack). This is -only a small subset of OpenGL 1.x, mainly intended for debug-visualization or -simple tasks like 2D UI rendering. As always, sample code is in the -[sokol-samples](https://github.com/floooh/sokol-samples) project. - -- **15-Mar-2019**: various Dear ImGui related changes: - - there's a new utility header sokol_imgui.h with a simple drop-in - renderer for Dear ImGui on top of sokol_gfx.h and sokol_app.h - (sokol_app.h is optional, and only used for input handling) - - the sokol_gfx_imgui.h debug inspection header no longer - depends on internal data structures and functions of sokol_gfx.h, as such - it is now a normal *utility header* and has been moved to the *utils* - directory - - the implementation macro for sokol_gfx_imgui.h has been changed - from SOKOL_IMPL to SOKOL_GFX_IMGUI_IMPL (so when you suddenly get - unresolved linker errors, that's the reason) - - all headers now have two preprocessor defines for the declaration - and implementation (for instance in sokol_gfx.h: SOKOL_GFX_INCLUDED - and SOKOL_GFX_IMPL_INCLUDED) these are checked in the utility-headers - to provide useful error message when dependent headers are missing - -- **05-Mar-2019**: sokol_gfx.h now has a 'trace hook' API, and I have started -implementing optional debug-inspection-UI headers on top of Dear ImGui: - - sokol_gfx.h has a new function *sg_install_trace_hooks()*, this allows - you to install a callback function for each public sokol_gfx.h function - (and a couple of error callbacks). For more details, search for "TRACE HOOKS" - in sokol_gfx.h - - when creating sokol_gfx.h resources, you can now set a 'debug label' - in the desc structure, this is ignored by sokol_gfx.h itself, but is - useful for debuggers or profilers hooking in via the new trace hooks - - likewise, two new functions *sg_push_debug_group()* and *sg_pop_debug_group()* - can be used to group related drawing functions under a name, this - is also ignored by sokol_gfx.h itself and only useful when hooking - into the API calls - - I have started a new 'subproject' in the 'imgui' directory, this will - contain a slowly growing set of optional debug-inspection-UI headers - which allow to peek under the hood of the Sokol headers. The UIs are - implemented with [Dear ImGui](https://github.com/ocornut/imgui). Again, - see the README in the 'imgui' directory and the headers in there - for details, and check out the live demos on the [Sokol Sample Webpage](https://floooh.github.io/sokol-html5/) - (click on the little UI buttons in the top right corner of each thumbnail) - -- **21-Feb-2019**: sokol_app.h and sokol_audio.h now have an alternative -set of callbacks with user_data arguments. This is useful if you don't -want or cannot store your own application state in global variables. -See the header documentation in sokol_app.h and sokol_audio.h for details, -and check out the samples *sapp/noentry-sapp.c* and *sapp/modplay-sapp.c* -in https://github.com/floooh/sokol-samples - -- **19-Feb-2019**: sokol_app.h now has an alternative mode where it doesn't -"hijack" the platform's main() function. Search for SOKOL_NO_ENTRY in -sokol_app.h for details and documentation. - -- **26-Jan-2019**: sokol_app.h now has an Android backend contributed by - [Gustav Olsson](https://github.com/gustavolsson)! - See the [sokol-samples readme](https://github.com/floooh/sokol-samples/blob/master/README.md) - for build instructions. - -- **21-Jan-2019**: sokol_gfx.h - pool-slot-generation-counters and a dummy backend: - - Resource pool slots now have a generation-counter for the resource-id - unique-tag, instead of a single counter for the whole pool. This allows - to create many more unique handles. - - sokol_gfx.h now has a dummy backend, activated by defining SOKOL_DUMMY_BACKEND - (instead of SOKOL_METAL, SOKOL_D3D11, ...), this allows to write - 'headless' tests (and there's now a sokol-gfx-test in the sokol-samples - repository which mainly tests the resource pool system) - -- **12-Jan-2019**: sokol_gfx.h - setting the pipeline state and resource -bindings now happens in separate calls, specifically: - - *sg_apply_draw_state()* has been replaced with *sg_apply_pipeline()* and - *sg_apply_bindings()* - - the *sg_draw_state* struct has been replaced with *sg_bindings* - - *sg_apply_uniform_block()* has been renamed to *sg_apply_uniforms()* - -All existing code will still work. See [this blog -post](https://floooh.github.io/2019/01/12/sokol-apply-pipeline.html) for -details. - -- **29-Oct-2018**: - - sokol_gfx.h has a new function **sg_append_buffer()** which allows to - append new data to a buffer multiple times per frame and interleave this - with draw calls. This basically implements the - D3D11_MAP_WRITE_NO_OVERWRITE update strategy for buffer objects. For - example usage, see the updated Dear ImGui samples in the [sokol_samples - repo](https://github.com/floooh/sokol-samples) - - the GL state cache in sokol_gfx.h handles buffers bindings in a - more robust way, previously it might have happened that the - buffer binding gets confused when creating buffers or updating - buffer contents in the render loop - -- **17-Oct-2018**: sokol_args.h added - -- **26-Sep-2018**: sokol_audio.h ready for prime time :) - -- **11-May-2018**: sokol_gfx.h now autodetects iOS vs MacOS in the Metal -backend during compilation using the standard define TARGET_OS_IPHONE defined -in the TargetConditionals.h system header, please replace the old -backend-selection defines SOKOL_METAL_MACOS and SOKOL_METAL_IOS with -**SOKOL_METAL** - -- **20-Apr-2018**: 3 new context-switching functions have been added -to make it possible to use sokol together with applications that -use multiple GL contexts. On D3D11 and Metal, the functions are currently -empty. See the new section ```WORKING WITH CONTEXTS``` in the sokol_gfx.h -header documentation, and the new sample [multiwindow-glfw](https://github.com/floooh/sokol-samples/blob/master/glfw/multiwindow-glfw.c) - -- **31-Jan-2018**: The vertex layout declaration in sg\_pipeline\_desc had -some fairly subtle flaws and has been changed to work like Metal or Vulkan. -The gist is that the vertex-buffer-layout properties (vertex stride, -vertex-step-rate and -step-function for instancing) is now defined in a -separate array from the vertex attributes. This removes some brittle backend -code which tries to guess the right vertex attribute slot if no attribute -names are given, and which was wrong for shader-code-generation pipelines -which reorder the vertex attributes (I stumbled over this when porting the -Oryol Gfx module over to sokol-gfx). Some code samples: - -```c -// a complete vertex layout declaration with a single input buffer -// with two vertex attributes -sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){ - .layout = { - .buffers = { - [0] = { - .stride = 20, - .step_func = SG_VERTEXSTEP_PER_VERTEX, - .step_rate = 1 - } - }, - .attrs = { - [0] = { - .name = "pos", - .offset = 0, - .format = SG_VERTEXFORMAT_FLOAT3, - .buffer_index = 0 - }, - [1] = { - .name = "uv", - .offset = 12, - .format = SG_VERTEXFORMAT_FLOAT2, - .buffer_index = 0 - } - } - }, - ... -}); - -// if the vertex layout has no gaps, we can get rid of the strides and offsets: -sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){ - .layout = { - .buffers = { - [0] = { - .step_func = SG_VERTEXSTEP_PER_VERTEX, - .step_rate=1 - } - }, - .attrs = { - [0] = { - .name = "pos", - .format = SG_VERTEXFORMAT_FLOAT3, - .buffer_index = 0 - }, - [1] = { - .name = "uv", - .format = SG_VERTEXFORMAT_FLOAT2, - .buffer_index = 0 - } - } - }, - ... -}); - -// we can also get rid of the other default-values, which leaves buffers[0] -// as all-defaults, so it can disappear completely: -sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){ - .layout = { - .attrs = { - [0] = { .name = "pos", .format = SG_VERTEXFORMAT_FLOAT3 }, - [1] = { .name = "uv", .format = SG_VERTEXFORMAT_FLOAT2 } - } - }, - ... -}); - -// and finally on GL3.3 and Metal and we don't need the attribute names -// (on D3D11, a semantic name and index must be provided though) -sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){ - .layout = { - .attrs = { - [0] = { .format = SG_VERTEXFORMAT_FLOAT3 }, - [1] = { .format = SG_VERTEXFORMAT_FLOAT2 } - } - }, - ... -}); -``` - -Please check the sample code in https://github.com/floooh/sokol-samples for -more examples! - -Enjoy! diff --git a/source/thirdparty/sokol/LICENSE b/source/thirdparty/sokol/LICENSE deleted file mode 100644 index efdc02e8..00000000 --- a/source/thirdparty/sokol/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -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. diff --git a/source/thirdparty/sokol/README.md b/source/thirdparty/sokol/README.md deleted file mode 100644 index c6ebd179..00000000 --- a/source/thirdparty/sokol/README.md +++ /dev/null @@ -1,406 +0,0 @@ -# Sokol - -Simple -[STB-style](https://github.com/nothings/stb/blob/master/docs/stb_howto.txt) -cross-platform libraries for C and C++, written in C. - -[**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**29-Feb-2024**: **BREAKING CHANGES** 'unified render pass' -cleanup in sokol_gfx.h) - -[![Build](/../../actions/workflows/main.yml/badge.svg)](/../../actions/workflows/main.yml) [![Bindings](/../../actions/workflows/gen_bindings.yml/badge.svg)](/../../actions/workflows/gen_bindings.yml) [![build](https://github.com/floooh/sokol-zig/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-zig/actions/workflows/main.yml) [![build](https://github.com/floooh/sokol-nim/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-nim/actions/workflows/main.yml) [![Odin](https://github.com/floooh/sokol-odin/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-odin/actions/workflows/main.yml)[![Rust](https://github.com/floooh/sokol-rust/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-rust/actions/workflows/main.yml) - -## Examples and Related Projects - -- [Live Samples](https://floooh.github.io/sokol-html5/index.html) via WASM ([source](https://github.com/floooh/sokol-samples)) - -- [Doom Shareware](https://floooh.github.io/doom-sokol/) ported to the Sokol headers ([source](https://github.com/floooh/doom-sokol)) - -- [sokol_gp.h](https://github.com/edubart/sokol_gp) a 2D shape drawing library on top of sokol_gfx.h - -- [LearnOpenGL examples ported to sokol-gfx](https://zeromake.github.io/learnopengl-examples/) ([git repo](https://github.com/zeromake/learnopengl-examples)) - -- [Dear ImGui starterkit](https://github.com/floooh/cimgui-sokol-starterkit) a self-contained starterkit for writing Dear ImGui apps in C. - -- [qoiview](https://github.com/floooh/qoiview) a basic viewer for the new QOI image file format - -- [Tiny 8-bit emulators](https://floooh.github.io/tiny8bit/) - -- A 'single-file' [Pacman clone in C99](https://github.com/floooh/pacman.c/), also available in [Zig](https://github.com/floooh/pacman.zig/) - -- [MEG-4](https://bztsrc.gitlab.io/meg4) a virtual fantasy console emulator in C89, ported to sokol - -- A [Minigolf game](https://mgerdes.github.io/minigolf.html) ([source](https://github.com/mgerdes/minigolf)). - -- ['Dealer's Dungeon'](https://dealers-dungeon.com/demo/) ([lower graphics quality](https://dealers-dungeon.com/demo/?q=3), -[source](https://github.com/bqqbarbhg/spear)) - -- [Command line tools](https://github.com/floooh/sokol-tools) (shader compiler) - -- [How to build without a build system](https://github.com/floooh/sokol-samples#how-to-build-without-a-build-system): -useful details for integrating the Sokol headers into your own project with your favourite C/C++ build system - -## Core libraries - -- [**sokol\_gfx.h**](https://github.com/floooh/sokol/blob/master/sokol_gfx.h): 3D-API wrapper (GL/GLES3/WebGL2 + Metal + D3D11 + WebGPU) -- [**sokol\_app.h**](https://github.com/floooh/sokol/blob/master/sokol_app.h): app framework wrapper (entry + window + 3D-context + input) -- [**sokol\_time.h**](https://github.com/floooh/sokol/blob/master/sokol_time.h): time measurement -- [**sokol\_audio.h**](https://github.com/floooh/sokol/blob/master/sokol_audio.h): minimal buffer-streaming audio playback -- [**sokol\_fetch.h**](https://github.com/floooh/sokol/blob/master/sokol_fetch.h): asynchronous data streaming from HTTP and local filesystem -- [**sokol\_args.h**](https://github.com/floooh/sokol/blob/master/sokol_args.h): unified cmdline/URL arg parser for web and native apps -- [**sokol\_log.h**](https://github.com/floooh/sokol/blob/master/sokol_log.h): provides a standard logging callback for the other sokol headers - -## Utility libraries - -- [**sokol\_imgui.h**](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h): sokol_gfx.h rendering backend for [Dear ImGui](https://github.com/ocornut/imgui) -- [**sokol\_nuklear.h**](https://github.com/floooh/sokol/blob/master/util/sokol_nuklear.h): sokol_gfx.h rendering backend for [Nuklear](https://github.com/Immediate-Mode-UI/Nuklear) -- [**sokol\_gl.h**](https://github.com/floooh/sokol/blob/master/util/sokol_gl.h): OpenGL 1.x style immediate-mode rendering API on top of sokol_gfx.h -- [**sokol\_fontstash.h**](https://github.com/floooh/sokol/blob/master/util/sokol_fontstash.h): sokol_gl.h rendering backend for [fontstash](https://github.com/memononen/fontstash) -- [**sokol\_gfx\_imgui.h**](https://github.com/floooh/sokol/blob/master/util/sokol_gfx_imgui.h): debug-inspection UI for sokol_gfx.h (implemented with Dear ImGui) -- [**sokol\_debugtext.h**](https://github.com/floooh/sokol/blob/master/util/sokol_debugtext.h): a simple text renderer using vintage home computer fonts -- [**sokol\_memtrack.h**](https://github.com/floooh/sokol/blob/master/util/sokol_memtrack.h): easily track memory allocations in sokol headers -- [**sokol\_shape.h**](https://github.com/floooh/sokol/blob/master/util/sokol_shape.h): generate simple shapes and plug them into sokol-gfx resource creation structs -- [**sokol\_color.h**](https://github.com/floooh/sokol/blob/master/util/sokol_color.h): X11 style color constants and functions for creating sg_color objects -- [**sokol\_spine.h**](https://github.com/floooh/sokol/blob/master/util/sokol_spine.h): a sokol-style wrapper around the Spine C runtime (http://en.esotericsoftware.com/spine-in-depth) - -## 'Official' Language Bindings - -These are automatically updated on changes to the C headers: - -- [sokol-zig](https://github.com/floooh/sokol-zig) -- [sokol-odin](https://github.com/floooh/sokol-odin) -- [sokol-nim](https://github.com/floooh/sokol-nim) -- [sokol-rust](https://github.com/floooh/sokol-rust) - -## Notes - -WebAssembly is a 'first-class citizen', one important motivation for the -Sokol headers is to provide a collection of cross-platform APIs with a -minimal footprint on the web platform while still being useful. - -The core headers are standalone and can be used independently from each other. - -### Why C: - -- easier integration with other languages -- easier integration into other projects -- adds only minimal size overhead to executables - -A blog post with more background info: [A Tour of sokol_gfx.h](http://floooh.github.io/2017/07/29/sokol-gfx-tour.html) - -# sokol_gfx.h: - -- simple, modern wrapper around GLES3/WebGL2, GL3.3, D3D11, Metal, and WebGPU -- buffers, images, shaders, pipeline-state-objects and render-passes -- does *not* handle window creation or 3D API context initialization -- does *not* provide shader dialect cross-translation (**BUT** there's now an 'official' shader-cross-compiler solution which -seamlessly integrates with sokol_gfx.h and IDEs: [see here for details](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md) - -# sokol_app.h - -A minimal cross-platform application-wrapper library: - -- unified application entry -- single window or canvas for 3D rendering -- 3D context initialization -- event-based keyboard, mouse and touch input -- supported platforms: Win32, MacOS, Linux (X11), iOS, WASM, Android, UWP -- supported 3D-APIs: GL3.3 (GLX/WGL), Metal, D3D11, GLES3/WebGL2 - -The vanilla Hello-Triangle using sokol_gfx.h, sokol_app.h and the -sokol-shdc shader compiler (shader code not shown): - -```c -#include "sokol_app.h" -#include "sokol_gfx.h" -#include "sokol_log.h" -#include "sokol_glue.h" -#include "triangle-sapp.glsl.h" - -static struct { - sg_pipeline pip; - sg_bindings bind; - sg_pass_action pass_action; -} state; - -static void init(void) { - sg_setup(&(sg_desc){ - .environment = sglue_environment(), - .logger.func = slog_func, - }); - - float vertices[] = { - 0.0f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f - }; - state.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ - .data = SG_RANGE(vertices), - }); - - state.pip = sg_make_pipeline(&(sg_pipeline_desc){ - .shader = sg_make_shader(triangle_shader_desc(sg_query_backend())), - .layout = { - .attrs = { - [ATTR_vs_position].format = SG_VERTEXFORMAT_FLOAT3, - [ATTR_vs_color0].format = SG_VERTEXFORMAT_FLOAT4 - } - }, - }); - - state.pass_action = (sg_pass_action) { - .colors[0] = { .load_action=SG_LOADACTION_CLEAR, .clear_value={0.0f, 0.0f, 0.0f, 1.0f } } - }; -} - -void frame(void) { - sg_begin_pass(&(sg_pass){ .action = state.pass_action, .swapchain = sglue_swapchain() }); - sg_apply_pipeline(state.pip); - sg_apply_bindings(&state.bind); - sg_draw(0, 3, 1); - sg_end_pass(); - sg_commit(); -} - -void cleanup(void) { - sg_shutdown(); -} - -sapp_desc sokol_main(int argc, char* argv[]) { - (void)argc; (void)argv; - return (sapp_desc){ - .init_cb = init, - .frame_cb = frame, - .cleanup_cb = cleanup, - .width = 640, - .height = 480, - .window_title = "Triangle", - .icon.sokol_default = true, - .logger.func = slog_func, - }; -} -``` - -# sokol_audio.h - -A minimal audio-streaming API: - -- you provide a mono- or stereo-stream of 32-bit float samples which sokol_audio.h forwards into platform-specific backends -- two ways to provide the data: - 1. directly fill backend audio buffer from your callback function running in the audio thread - 2. alternatively push small packets of audio data from your main loop, - or a separate thread created by you -- platform backends: - - Windows: WASAPI - - macOS/iOS: CoreAudio - - Linux: ALSA - - emscripten: WebAudio + ScriptProcessorNode (doesn't use the emscripten-provided OpenAL or SDL Audio wrappers) - -A simple mono square-wave generator using the callback model: - -```c -// the sample callback, running in audio thread -static void stream_cb(float* buffer, int num_frames, int num_channels) { - assert(1 == num_channels); - static uint32_t count = 0; - for (int i = 0; i < num_frames; i++) { - buffer[i] = (count++ & (1<<3)) ? 0.5f : -0.5f; - } -} - -int main() { - // init sokol-audio with default params - saudio_setup(&(saudio_desc){ - .stream_cb = stream_cb, - .logger.func = slog_func, - }); - - // run main loop - ... - - // shutdown sokol-audio - saudio_shutdown(); - return 0; -``` - -The same code using the push-model - -```c -#define BUF_SIZE (32) -int main() { - // init sokol-audio with default params, no callback - saudio_setup(&(saudio_desc){ - .logger.func = slog_func, - }); - assert(saudio_channels() == 1); - - // a small intermediate buffer so we don't need to push - // individual samples, which would be quite inefficient - float buf[BUF_SIZE]; - int buf_pos = 0; - uint32_t count = 0; - - // push samples from main loop - bool done = false; - while (!done) { - // generate and push audio samples... - int num_frames = saudio_expect(); - for (int i = 0; i < num_frames; i++) { - // simple square wave generator - buf[buf_pos++] = (count++ & (1<<3)) ? 0.5f : -0.5f; - if (buf_pos == BUF_SIZE) { - buf_pos = 0; - saudio_push(buf, BUF_SIZE); - } - } - // handle other per-frame stuff... - ... - } - - // shutdown sokol-audio - saudio_shutdown(); - return 0; -} -``` - -# sokol_fetch.h - -Load entire files, or stream data asynchronously over HTTP (emscripten/wasm) -or the local filesystem (all native platforms). - -Simple C99 example loading a file into a static buffer: - -```c -#include "sokol_fetch.h" -#include "sokol_log.h" - -static void response_callback(const sfetch_response*); - -#define MAX_FILE_SIZE (1024*1024) -static uint8_t buffer[MAX_FILE_SIZE]; - -// application init -static void init(void) { - ... - // setup sokol-fetch with default config: - sfetch_setup(&(sfetch_desc_t){ .logger.func = slog_func }); - - // start loading a file into a statically allocated buffer: - sfetch_send(&(sfetch_request_t){ - .path = "hello_world.txt", - .callback = response_callback - .buffer_ptr = buffer, - .buffer_size = sizeof(buffer) - }); -} - -// per frame... -static void frame(void) { - ... - // need to call sfetch_dowork() once per frame to 'turn the gears': - sfetch_dowork(); - ... -} - -// the response callback is where the interesting stuff happens: -static void response_callback(const sfetch_response_t* response) { - if (response->fetched) { - // data has been loaded into the provided buffer, do something - // with the data... - const void* data = response->buffer_ptr; - uint64_t data_size = response->fetched_size; - } - // the finished flag is set both on success and failure - if (response->failed) { - // oops, something went wrong - switch (response->error_code) { - SFETCH_ERROR_FILE_NOT_FOUND: ... - SFETCH_ERROR_BUFFER_TOO_SMALL: ... - ... - } - } -} - -// application shutdown -static void shutdown(void) { - ... - sfetch_shutdown(); - ... -} -``` - -# sokol_time.h: - -Simple cross-platform time measurement: - -```c -#include "sokol_time.h" -... -/* initialize sokol_time */ -stm_setup(); - -/* take start timestamp */ -uint64_t start = stm_now(); - -...some code to measure... - -/* compute elapsed time */ -uint64_t elapsed = stm_since(start); - -/* convert to time units */ -double seconds = stm_sec(elapsed); -double milliseconds = stm_ms(elapsed); -double microseconds = stm_us(elapsed); -double nanoseconds = stm_ns(elapsed); - -/* difference between 2 time stamps */ -uint64_t start = stm_now(); -... -uint64_t end = stm_now(); -uint64_t elapsed = stm_diff(end, start); - -/* compute a 'lap time' (e.g. for fps) */ -uint64_t last_time = 0; -while (!done) { - ...render something... - double frame_time_ms = stm_ms(stm_laptime(&last_time)); -} -``` - -# sokol_args.h - -Unified argument parsing for web and native apps. Uses argc/argv on native -platforms and the URL query string on the web. - -Example URL with one arg: - -https://floooh.github.io/tiny8bit/kc85.html?type=kc85_4 - -The same as command line app: - -> kc85 type=kc85_4 - -Parsed like this: - -```c -#include "sokol_args.h" - -int main(int argc, char* argv[]) { - sargs_setup(&(sargs_desc){ .argc=argc, .argv=argv }); - if (sargs_exists("type")) { - if (sargs_equals("type", "kc85_4")) { - // start as KC85/4 - } - else if (sargs_equals("type", "kc85_3")) { - // start as KC85/3 - } - else { - // start as KC85/2 - } - } - sargs_shutdown(); - return 0; -} -``` - -See the sokol_args.h header for a more complete documentation, and the [Tiny -Emulators](https://floooh.github.io/tiny8bit/) for more interesting usage examples. diff --git a/source/thirdparty/sokol/fips.yml b/source/thirdparty/sokol/fips.yml deleted file mode 100644 index 372d8fd5..00000000 --- a/source/thirdparty/sokol/fips.yml +++ /dev/null @@ -1,2 +0,0 @@ -exports: - header-dirs: [ ".", "util" ] diff --git a/source/thirdparty/sokol/sokol_app.h b/source/thirdparty/sokol/sokol_app.h deleted file mode 100644 index 7cd29bf8..00000000 --- a/source/thirdparty/sokol/sokol_app.h +++ /dev/null @@ -1,12097 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_APP_IMPL) -#define SOKOL_APP_IMPL -#endif -#ifndef SOKOL_APP_INCLUDED -/* - sokol_app.h -- cross-platform application wrapper - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_APP_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - In the same place define one of the following to select the 3D-API - which should be initialized by sokol_app.h (this must also match - the backend selected for sokol_gfx.h if both are used in the same - project): - - #define SOKOL_GLCORE - #define SOKOL_GLES3 - #define SOKOL_D3D11 - #define SOKOL_METAL - #define SOKOL_WGPU - #define SOKOL_NOAPI - - Optionally provide the following defines with your own implementations: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - SOKOL_WIN32_FORCE_MAIN - define this on Win32 to use a main() entry point instead of WinMain - SOKOL_NO_ENTRY - define this if sokol_app.h shouldn't "hijack" the main() function - SOKOL_APP_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_APP_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - Optionally define the following to force debug checks and validations - even in release mode: - - SOKOL_DEBUG - by default this is defined if _DEBUG is defined - - If sokol_app.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_APP_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - On Linux, SOKOL_GLCORE can use either GLX or EGL. - GLX is default, set SOKOL_FORCE_EGL to override. - - For example code, see https://github.com/floooh/sokol-samples/tree/master/sapp - - Portions of the Windows and Linux GL initialization, event-, icon- etc... code - have been taken from GLFW (http://www.glfw.org/). - - iOS onscreen keyboard support 'inspired' by libgdx. - - Link with the following system libraries: - - - on macOS with Metal: Cocoa, QuartzCore, Metal, MetalKit - - on macOS with GL: Cocoa, QuartzCore, OpenGL - - on iOS with Metal: Foundation, UIKit, Metal, MetalKit - - on iOS with GL: Foundation, UIKit, OpenGLES, GLKit - - on Linux with EGL: X11, Xi, Xcursor, EGL, GL (or GLESv2), dl, pthread, m(?) - - on Linux with GLX: X11, Xi, Xcursor, GL, dl, pthread, m(?) - - on Android: GLESv3, EGL, log, android - - on Windows with the MSVC or Clang toolchains: no action needed, libs are defined in-source via pragma-comment-lib - - on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' so that _WIN32 is defined - - link with the following libs: -lkernel32 -luser32 -lshell32 - - additionally with the GL backend: -lgdi32 - - additionally with the D3D11 backend: -ld3d11 -ldxgi - - On Linux, you also need to use the -pthread compiler and linker option, otherwise weird - things will happen, see here for details: https://github.com/floooh/sokol/issues/376 - - On macOS and iOS, the implementation must be compiled as Objective-C. - - FEATURE OVERVIEW - ================ - sokol_app.h provides a minimalistic cross-platform API which - implements the 'application-wrapper' parts of a 3D application: - - - a common application entry function - - creates a window and 3D-API context/device with a 'default framebuffer' - - makes the rendered frame visible - - provides keyboard-, mouse- and low-level touch-events - - platforms: MacOS, iOS, HTML5, Win32, Linux/RaspberryPi, Android - - 3D-APIs: Metal, D3D11, GL4.1, GL4.3, GLES3, WebGL, WebGL2, NOAPI - - FEATURE/PLATFORM MATRIX - ======================= - | Windows | macOS | Linux | iOS | Android | HTML5 - --------------------+---------+-------+-------+-------+---------+-------- - gl 3.x | YES | YES | YES | --- | --- | --- - gles3/webgl2 | --- | --- | YES(2)| YES | YES | YES - metal | --- | YES | --- | YES | --- | --- - d3d11 | YES | --- | --- | --- | --- | --- - noapi | YES | TODO | TODO | --- | TODO | --- - KEY_DOWN | YES | YES | YES | SOME | TODO | YES - KEY_UP | YES | YES | YES | SOME | TODO | YES - CHAR | YES | YES | YES | YES | TODO | YES - MOUSE_DOWN | YES | YES | YES | --- | --- | YES - MOUSE_UP | YES | YES | YES | --- | --- | YES - MOUSE_SCROLL | YES | YES | YES | --- | --- | YES - MOUSE_MOVE | YES | YES | YES | --- | --- | YES - MOUSE_ENTER | YES | YES | YES | --- | --- | YES - MOUSE_LEAVE | YES | YES | YES | --- | --- | YES - TOUCHES_BEGAN | --- | --- | --- | YES | YES | YES - TOUCHES_MOVED | --- | --- | --- | YES | YES | YES - TOUCHES_ENDED | --- | --- | --- | YES | YES | YES - TOUCHES_CANCELLED | --- | --- | --- | YES | YES | YES - RESIZED | YES | YES | YES | YES | YES | YES - ICONIFIED | YES | YES | YES | --- | --- | --- - RESTORED | YES | YES | YES | --- | --- | --- - FOCUSED | YES | YES | YES | --- | --- | YES - UNFOCUSED | YES | YES | YES | --- | --- | YES - SUSPENDED | --- | --- | --- | YES | YES | TODO - RESUMED | --- | --- | --- | YES | YES | TODO - QUIT_REQUESTED | YES | YES | YES | --- | --- | YES - IME | TODO | TODO? | TODO | ??? | TODO | ??? - key repeat flag | YES | YES | YES | --- | --- | YES - windowed | YES | YES | YES | --- | --- | YES - fullscreen | YES | YES | YES | YES | YES | --- - mouse hide | YES | YES | YES | --- | --- | YES - mouse lock | YES | YES | YES | --- | --- | YES - set cursor type | YES | YES | YES | --- | --- | YES - screen keyboard | --- | --- | --- | YES | TODO | YES - swap interval | YES | YES | YES | YES | TODO | YES - high-dpi | YES | YES | TODO | YES | YES | YES - clipboard | YES | YES | TODO | --- | --- | YES - MSAA | YES | YES | YES | YES | YES | YES - drag'n'drop | YES | YES | YES | --- | --- | YES - window icon | YES | YES(1)| YES | --- | --- | YES - - (1) macOS has no regular window icons, instead the dock icon is changed - (2) supported with EGL only (not GLX) - - STEP BY STEP - ============ - --- Add a sokol_main() function to your code which returns a sapp_desc structure - with initialization parameters and callback function pointers. This - function is called very early, usually at the start of the - platform's entry function (e.g. main or WinMain). You should do as - little as possible here, since the rest of your code might be called - from another thread (this depends on the platform): - - sapp_desc sokol_main(int argc, char* argv[]) { - return (sapp_desc) { - .width = 640, - .height = 480, - .init_cb = my_init_func, - .frame_cb = my_frame_func, - .cleanup_cb = my_cleanup_func, - .event_cb = my_event_func, - ... - }; - } - - To get any logging output in case of errors you need to provide a log - callback. The easiest way is via sokol_log.h: - - #include "sokol_log.h" - - sapp_desc sokol_main(int argc, char* argv[]) { - return (sapp_desc) { - ... - .logger.func = slog_func, - }; - } - - There are many more setup parameters, but these are the most important. - For a complete list search for the sapp_desc structure declaration - below. - - DO NOT call any sokol-app function from inside sokol_main(), since - sokol-app will not be initialized at this point. - - The .width and .height parameters are the preferred size of the 3D - rendering canvas. The actual size may differ from this depending on - platform and other circumstances. Also the canvas size may change at - any time (for instance when the user resizes the application window, - or rotates the mobile device). You can just keep .width and .height - zero-initialized to open a default-sized window (what "default-size" - exactly means is platform-specific, but usually it's a size that covers - most of, but not all, of the display). - - All provided function callbacks will be called from the same thread, - but this may be different from the thread where sokol_main() was called. - - .init_cb (void (*)(void)) - This function is called once after the application window, - 3D rendering context and swap chain have been created. The - function takes no arguments and has no return value. - .frame_cb (void (*)(void)) - This is the per-frame callback, which is usually called 60 - times per second. This is where your application would update - most of its state and perform all rendering. - .cleanup_cb (void (*)(void)) - The cleanup callback is called once right before the application - quits. - .event_cb (void (*)(const sapp_event* event)) - The event callback is mainly for input handling, but is also - used to communicate other types of events to the application. Keep the - event_cb struct member zero-initialized if your application doesn't require - event handling. - - As you can see, those 'standard callbacks' don't have a user_data - argument, so any data that needs to be preserved between callbacks - must live in global variables. If keeping state in global variables - is not an option, there's an alternative set of callbacks with - an additional user_data pointer argument: - - .user_data (void*) - The user-data argument for the callbacks below - .init_userdata_cb (void (*)(void* user_data)) - .frame_userdata_cb (void (*)(void* user_data)) - .cleanup_userdata_cb (void (*)(void* user_data)) - .event_userdata_cb (void(*)(const sapp_event* event, void* user_data)) - - The function sapp_userdata() can be used to query the user_data - pointer provided in the sapp_desc struct. - - You can also call sapp_query_desc() to get a copy of the - original sapp_desc structure. - - NOTE that there's also an alternative compile mode where sokol_app.h - doesn't "hijack" the main() function. Search below for SOKOL_NO_ENTRY. - - --- Implement the initialization callback function (init_cb), this is called - once after the rendering surface, 3D API and swap chain have been - initialized by sokol_app. All sokol-app functions can be called - from inside the initialization callback, the most useful functions - at this point are: - - int sapp_width(void) - int sapp_height(void) - Returns the current width and height of the default framebuffer in pixels, - this may change from one frame to the next, and it may be different - from the initial size provided in the sapp_desc struct. - - float sapp_widthf(void) - float sapp_heightf(void) - These are alternatives to sapp_width() and sapp_height() which return - the default framebuffer size as float values instead of integer. This - may help to prevent casting back and forth between int and float - in more strongly typed languages than C and C++. - - double sapp_frame_duration(void) - Returns the frame duration in seconds averaged over a number of - frames to smooth out any jittering spikes. - - int sapp_color_format(void) - int sapp_depth_format(void) - The color and depth-stencil pixelformats of the default framebuffer, - as integer values which are compatible with sokol-gfx's - sg_pixel_format enum (so that they can be plugged directly in places - where sg_pixel_format is expected). Possible values are: - - 23 == SG_PIXELFORMAT_RGBA8 - 28 == SG_PIXELFORMAT_BGRA8 - 42 == SG_PIXELFORMAT_DEPTH - 43 == SG_PIXELFORMAT_DEPTH_STENCIL - - int sapp_sample_count(void) - Return the MSAA sample count of the default framebuffer. - - const void* sapp_metal_get_device(void) - const void* sapp_metal_get_current_drawable(void) - const void* sapp_metal_get_depth_stencil_texture(void) - const void* sapp_metal_get_msaa_color_texture(void) - If the Metal backend has been selected, these functions return pointers - to various Metal API objects required for rendering, otherwise - they return a null pointer. These void pointers are actually - Objective-C ids converted with a (ARC) __bridge cast so that - the ids can be tunnel through C code. Also note that the returned - pointers to the renderpass-descriptor and drawable may change from one - frame to the next, only the Metal device object is guaranteed to - stay the same. - - const void* sapp_macos_get_window(void) - On macOS, get the NSWindow object pointer, otherwise a null pointer. - Before being used as Objective-C object, the void* must be converted - back with a (ARC) __bridge cast. - - const void* sapp_ios_get_window(void) - On iOS, get the UIWindow object pointer, otherwise a null pointer. - Before being used as Objective-C object, the void* must be converted - back with a (ARC) __bridge cast. - - const void* sapp_d3d11_get_device(void) - const void* sapp_d3d11_get_device_context(void) - const void* sapp_d3d11_get_render_view(void) - const void* sapp_d3d11_get_resolve_view(void); - const void* sapp_d3d11_get_depth_stencil_view(void) - Similar to the sapp_metal_* functions, the sapp_d3d11_* functions - return pointers to D3D11 API objects required for rendering, - only if the D3D11 backend has been selected. Otherwise they - return a null pointer. Note that the returned pointers to the - render-target-view and depth-stencil-view may change from one - frame to the next! - - const void* sapp_win32_get_hwnd(void) - On Windows, get the window's HWND, otherwise a null pointer. The - HWND has been cast to a void pointer in order to be tunneled - through code which doesn't include Windows.h. - - const void* sapp_wgpu_get_device(void) - const void* sapp_wgpu_get_render_view(void) - const void* sapp_wgpu_get_resolve_view(void) - const void* sapp_wgpu_get_depth_stencil_view(void) - These are the WebGPU-specific functions to get the WebGPU - objects and values required for rendering. If sokol_app.h - is not compiled with SOKOL_WGPU, these functions return null. - - uint32_t sapp_gl_get_framebuffer(void) - This returns the 'default framebuffer' of the GL context. - Typically this will be zero. - - int sapp_gl_get_major_version(void) - int sapp_gl_get_minor_version(void) - Returns the major and minor version of the GL context - (only for SOKOL_GLCORE, all other backends return zero here, including SOKOL_GLES3) - - const void* sapp_android_get_native_activity(void); - On Android, get the native activity ANativeActivity pointer, otherwise - a null pointer. - - --- Implement the frame-callback function, this function will be called - on the same thread as the init callback, but might be on a different - thread than the sokol_main() function. Note that the size of - the rendering framebuffer might have changed since the frame callback - was called last. Call the functions sapp_width() and sapp_height() - each frame to get the current size. - - --- Optionally implement the event-callback to handle input events. - sokol-app provides the following type of input events: - - a 'virtual key' was pressed down or released - - a single text character was entered (provided as UTF-32 code point) - - a mouse button was pressed down or released (left, right, middle) - - mouse-wheel or 2D scrolling events - - the mouse was moved - - the mouse has entered or left the application window boundaries - - low-level, portable multi-touch events (began, moved, ended, cancelled) - - the application window was resized, iconified or restored - - the application was suspended or restored (on mobile platforms) - - the user or application code has asked to quit the application - - a string was pasted to the system clipboard - - one or more files have been dropped onto the application window - - To explicitly 'consume' an event and prevent that the event is - forwarded for further handling to the operating system, call - sapp_consume_event() from inside the event handler (NOTE that - this behaviour is currently only implemented for some HTML5 - events, support for other platforms and event types will - be added as needed, please open a GitHub ticket and/or provide - a PR if needed). - - NOTE: Do *not* call any 3D API rendering functions in the event - callback function, since the 3D API context may not be active when the - event callback is called (it may work on some platforms and 3D APIs, - but not others, and the exact behaviour may change between - sokol-app versions). - - --- Implement the cleanup-callback function, this is called once - after the user quits the application (see the section - "APPLICATION QUIT" for detailed information on quitting - behaviour, and how to intercept a pending quit - for instance to show a - "Really Quit?" dialog box). Note that the cleanup-callback isn't - guaranteed to be called on the web and mobile platforms. - - MOUSE CURSOR TYPE AND VISIBILITY - ================================ - You can show and hide the mouse cursor with - - void sapp_show_mouse(bool show) - - And to get the current shown status: - - bool sapp_mouse_shown(void) - - NOTE that hiding the mouse cursor is different and independent from - the MOUSE/POINTER LOCK feature which will also hide the mouse pointer when - active (MOUSE LOCK is described below). - - To change the mouse cursor to one of several predefined types, call - the function: - - void sapp_set_mouse_cursor(sapp_mouse_cursor cursor) - - Setting the default mouse cursor SAPP_MOUSECURSOR_DEFAULT will restore - the standard look. - - To get the currently active mouse cursor type, call: - - sapp_mouse_cursor sapp_get_mouse_cursor(void) - - MOUSE LOCK (AKA POINTER LOCK, AKA MOUSE CAPTURE) - ================================================ - In normal mouse mode, no mouse movement events are reported when the - mouse leaves the windows client area or hits the screen border (whether - it's one or the other depends on the platform), and the mouse move events - (SAPP_EVENTTYPE_MOUSE_MOVE) contain absolute mouse positions in - framebuffer pixels in the sapp_event items mouse_x and mouse_y, and - relative movement in framebuffer pixels in the sapp_event items mouse_dx - and mouse_dy. - - To get continuous mouse movement (also when the mouse leaves the window - client area or hits the screen border), activate mouse-lock mode - by calling: - - sapp_lock_mouse(true) - - When mouse lock is activated, the mouse pointer is hidden, the - reported absolute mouse position (sapp_event.mouse_x/y) appears - frozen, and the relative mouse movement in sapp_event.mouse_dx/dy - no longer has a direct relation to framebuffer pixels but instead - uses "raw mouse input" (what "raw mouse input" exactly means also - differs by platform). - - To deactivate mouse lock and return to normal mouse mode, call - - sapp_lock_mouse(false) - - And finally, to check if mouse lock is currently active, call - - if (sapp_mouse_locked()) { ... } - - On native platforms, the sapp_lock_mouse() and sapp_mouse_locked() - functions work as expected (mouse lock is activated or deactivated - immediately when sapp_lock_mouse() is called, and sapp_mouse_locked() - also immediately returns the new state after sapp_lock_mouse() - is called. - - On the web platform, sapp_lock_mouse() and sapp_mouse_locked() behave - differently, as dictated by the limitations of the HTML5 Pointer Lock API: - - - sapp_lock_mouse(true) can be called at any time, but it will - only take effect in a 'short-lived input event handler of a specific - type', meaning when one of the following events happens: - - SAPP_EVENTTYPE_MOUSE_DOWN - - SAPP_EVENTTYPE_MOUSE_UP - - SAPP_EVENTTYPE_MOUSE_SCROLL - - SAPP_EVENTTYPE_KEY_UP - - SAPP_EVENTTYPE_KEY_DOWN - - The mouse lock/unlock action on the web platform is asynchronous, - this means that sapp_mouse_locked() won't immediately return - the new status after calling sapp_lock_mouse(), instead the - reported status will only change when the pointer lock has actually - been activated or deactivated in the browser. - - On the web, mouse lock can be deactivated by the user at any time - by pressing the Esc key. When this happens, sokol_app.h behaves - the same as if sapp_lock_mouse(false) is called. - - For things like camera manipulation it's most straightforward to lock - and unlock the mouse right from the sokol_app.h event handler, for - instance the following code enters and leaves mouse lock when the - left mouse button is pressed and released, and then uses the relative - movement information to manipulate a camera (taken from the - cgltf-sapp.c sample in the sokol-samples repository - at https://github.com/floooh/sokol-samples): - - static void input(const sapp_event* ev) { - switch (ev->type) { - case SAPP_EVENTTYPE_MOUSE_DOWN: - if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) { - sapp_lock_mouse(true); - } - break; - - case SAPP_EVENTTYPE_MOUSE_UP: - if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) { - sapp_lock_mouse(false); - } - break; - - case SAPP_EVENTTYPE_MOUSE_MOVE: - if (sapp_mouse_locked()) { - cam_orbit(&state.camera, ev->mouse_dx * 0.25f, ev->mouse_dy * 0.25f); - } - break; - - default: - break; - } - } - - CLIPBOARD SUPPORT - ================= - Applications can send and receive UTF-8 encoded text data from and to the - system clipboard. By default, clipboard support is disabled and - must be enabled at startup via the following sapp_desc struct - members: - - sapp_desc.enable_clipboard - set to true to enable clipboard support - sapp_desc.clipboard_size - size of the internal clipboard buffer in bytes - - Enabling the clipboard will dynamically allocate a clipboard buffer - for UTF-8 encoded text data of the requested size in bytes, the default - size is 8 KBytes. Strings that don't fit into the clipboard buffer - (including the terminating zero) will be silently clipped, so it's - important that you provide a big enough clipboard size for your - use case. - - To send data to the clipboard, call sapp_set_clipboard_string() with - a pointer to an UTF-8 encoded, null-terminated C-string. - - NOTE that on the HTML5 platform, sapp_set_clipboard_string() must be - called from inside a 'short-lived event handler', and there are a few - other HTML5-specific caveats to workaround. You'll basically have to - tinker until it works in all browsers :/ (maybe the situation will - improve when all browsers agree on and implement the new - HTML5 navigator.clipboard API). - - To get data from the clipboard, check for the SAPP_EVENTTYPE_CLIPBOARD_PASTED - event in your event handler function, and then call sapp_get_clipboard_string() - to obtain the pasted UTF-8 encoded text. - - NOTE that behaviour of sapp_get_clipboard_string() is slightly different - depending on platform: - - - on the HTML5 platform, the internal clipboard buffer will only be updated - right before the SAPP_EVENTTYPE_CLIPBOARD_PASTED event is sent, - and sapp_get_clipboard_string() will simply return the current content - of the clipboard buffer - - on 'native' platforms, the call to sapp_get_clipboard_string() will - update the internal clipboard buffer with the most recent data - from the system clipboard - - Portable code should check for the SAPP_EVENTTYPE_CLIPBOARD_PASTED event, - and then call sapp_get_clipboard_string() right in the event handler. - - The SAPP_EVENTTYPE_CLIPBOARD_PASTED event will be generated by sokol-app - as follows: - - - on macOS: when the Cmd+V key is pressed down - - on HTML5: when the browser sends a 'paste' event to the global 'window' object - - on all other platforms: when the Ctrl+V key is pressed down - - DRAG AND DROP SUPPORT - ===================== - PLEASE NOTE: the drag'n'drop feature works differently on WASM/HTML5 - and on the native desktop platforms (Win32, Linux and macOS) because - of security-related restrictions in the HTML5 drag'n'drop API. The - WASM/HTML5 specifics are described at the end of this documentation - section: - - Like clipboard support, drag'n'drop support must be explicitly enabled - at startup in the sapp_desc struct. - - sapp_desc sokol_main(void) { - return (sapp_desc) { - .enable_dragndrop = true, // default is false - ... - }; - } - - You can also adjust the maximum number of files that are accepted - in a drop operation, and the maximum path length in bytes if needed: - - sapp_desc sokol_main(void) { - return (sapp_desc) { - .enable_dragndrop = true, // default is false - .max_dropped_files = 8, // default is 1 - .max_dropped_file_path_length = 8192, // in bytes, default is 2048 - ... - }; - } - - When drag'n'drop is enabled, the event callback will be invoked with an - event of type SAPP_EVENTTYPE_FILES_DROPPED whenever the user drops files on - the application window. - - After the SAPP_EVENTTYPE_FILES_DROPPED is received, you can query the - number of dropped files, and their absolute paths by calling separate - functions: - - void on_event(const sapp_event* ev) { - if (ev->type == SAPP_EVENTTYPE_FILES_DROPPED) { - - // the mouse position where the drop happened - float x = ev->mouse_x; - float y = ev->mouse_y; - - // get the number of files and their paths like this: - const int num_dropped_files = sapp_get_num_dropped_files(); - for (int i = 0; i < num_dropped_files; i++) { - const char* path = sapp_get_dropped_file_path(i); - ... - } - } - } - - The returned file paths are UTF-8 encoded strings. - - You can call sapp_get_num_dropped_files() and sapp_get_dropped_file_path() - anywhere, also outside the event handler callback, but be aware that the - file path strings will be overwritten with the next drop operation. - - In any case, sapp_get_dropped_file_path() will never return a null pointer, - instead an empty string "" will be returned if the drag'n'drop feature - hasn't been enabled, the last drop-operation failed, or the file path index - is out of range. - - Drag'n'drop caveats: - - - if more files are dropped in a single drop-action - than sapp_desc.max_dropped_files, the additional - files will be silently ignored - - if any of the file paths is longer than - sapp_desc.max_dropped_file_path_length (in number of bytes, after UTF-8 - encoding) the entire drop operation will be silently ignored (this - needs some sort of error feedback in the future) - - no mouse positions are reported while the drag is in - process, this may change in the future - - Drag'n'drop on HTML5/WASM: - - The HTML5 drag'n'drop API doesn't return file paths, but instead - black-box 'file objects' which must be used to load the content - of dropped files. This is the reason why sokol_app.h adds two - HTML5-specific functions to the drag'n'drop API: - - uint32_t sapp_html5_get_dropped_file_size(int index) - Returns the size in bytes of a dropped file. - - void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) - Asynchronously loads the content of a dropped file into a - provided memory buffer (which must be big enough to hold - the file content) - - To start loading the first dropped file after an SAPP_EVENTTYPE_FILES_DROPPED - event is received: - - sapp_html5_fetch_dropped_file(&(sapp_html5_fetch_request){ - .dropped_file_index = 0, - .callback = fetch_cb - .buffer = { - .ptr = buf, - .size = sizeof(buf) - }, - .user_data = ... - }); - - Make sure that the memory pointed to by 'buf' stays valid until the - callback function is called! - - As result of the asynchronous loading operation (no matter if succeeded or - failed) the 'fetch_cb' function will be called: - - void fetch_cb(const sapp_html5_fetch_response* response) { - // IMPORTANT: check if the loading operation actually succeeded: - if (response->succeeded) { - // the size of the loaded file: - const size_t num_bytes = response->data.size; - // and the pointer to the data (same as 'buf' in the fetch-call): - const void* ptr = response->data.ptr; - } - else { - // on error check the error code: - switch (response->error_code) { - case SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL: - ... - break; - case SAPP_HTML5_FETCH_ERROR_OTHER: - ... - break; - } - } - } - - Check the droptest-sapp example for a real-world example which works - both on native platforms and the web: - - https://github.com/floooh/sokol-samples/blob/master/sapp/droptest-sapp.c - - HIGH-DPI RENDERING - ================== - You can set the sapp_desc.high_dpi flag during initialization to request - a full-resolution framebuffer on HighDPI displays. The default behaviour - is sapp_desc.high_dpi=false, this means that the application will - render to a lower-resolution framebuffer on HighDPI displays and the - rendered content will be upscaled by the window system composer. - - In a HighDPI scenario, you still request the same window size during - sokol_main(), but the framebuffer sizes returned by sapp_width() - and sapp_height() will be scaled up according to the DPI scaling - ratio. - - Note that on some platforms the DPI scaling factor may change at any - time (for instance when a window is moved from a high-dpi display - to a low-dpi display). - - To query the current DPI scaling factor, call the function: - - float sapp_dpi_scale(void); - - For instance on a Retina Mac, returning the following sapp_desc - struct from sokol_main(): - - sapp_desc sokol_main(void) { - return (sapp_desc) { - .width = 640, - .height = 480, - .high_dpi = true, - ... - }; - } - - ...the functions the functions sapp_width(), sapp_height() - and sapp_dpi_scale() will return the following values: - - sapp_width: 1280 - sapp_height: 960 - sapp_dpi_scale: 2.0 - - If the high_dpi flag is false, or you're not running on a Retina display, - the values would be: - - sapp_width: 640 - sapp_height: 480 - sapp_dpi_scale: 1.0 - - If the window is moved from the Retina display to a low-dpi external display, - the values would change as follows: - - sapp_width: 1280 => 640 - sapp_height: 960 => 480 - sapp_dpi_scale: 2.0 => 1.0 - - Currently there is no event associated with a DPI change, but an - SAPP_EVENTTYPE_RESIZED will be sent as a side effect of the - framebuffer size changing. - - Per-monitor DPI is currently supported on macOS and Windows. - - APPLICATION QUIT - ================ - Without special quit handling, a sokol_app.h application will quit - 'gracefully' when the user clicks the window close-button unless a - platform's application model prevents this (e.g. on web or mobile). - 'Graceful exit' means that the application-provided cleanup callback will - be called before the application quits. - - On native desktop platforms sokol_app.h provides more control over the - application-quit-process. It's possible to initiate a 'programmatic quit' - from the application code, and a quit initiated by the application user can - be intercepted (for instance to show a custom dialog box). - - This 'programmatic quit protocol' is implemented through 3 functions - and 1 event: - - - sapp_quit(): This function simply quits the application without - giving the user a chance to intervene. Usually this might - be called when the user clicks the 'Ok' button in a 'Really Quit?' - dialog box - - sapp_request_quit(): Calling sapp_request_quit() will send the - event SAPP_EVENTTYPE_QUIT_REQUESTED to the applications event handler - callback, giving the user code a chance to intervene and cancel the - pending quit process (for instance to show a 'Really Quit?' dialog - box). If the event handler callback does nothing, the application - will be quit as usual. To prevent this, call the function - sapp_cancel_quit() from inside the event handler. - - sapp_cancel_quit(): Cancels a pending quit request, either initiated - by the user clicking the window close button, or programmatically - by calling sapp_request_quit(). The only place where calling this - function makes sense is from inside the event handler callback when - the SAPP_EVENTTYPE_QUIT_REQUESTED event has been received. - - SAPP_EVENTTYPE_QUIT_REQUESTED: this event is sent when the user - clicks the window's close button or application code calls the - sapp_request_quit() function. The event handler callback code can handle - this event by calling sapp_cancel_quit() to cancel the quit. - If the event is ignored, the application will quit as usual. - - On the web platform, the quit behaviour differs from native platforms, - because of web-specific restrictions: - - A `programmatic quit` initiated by calling sapp_quit() or - sapp_request_quit() will work as described above: the cleanup callback is - called, platform-specific cleanup is performed (on the web - this means that JS event handlers are unregistered), and then - the request-animation-loop will be exited. However that's all. The - web page itself will continue to exist (e.g. it's not possible to - programmatically close the browser tab). - - On the web it's also not possible to run custom code when the user - closes a browser tab, so it's not possible to prevent this with a - fancy custom dialog box. - - Instead the standard "Leave Site?" dialog box can be activated (or - deactivated) with the following function: - - sapp_html5_ask_leave_site(bool ask); - - The initial state of the associated internal flag can be provided - at startup via sapp_desc.html5_ask_leave_site. - - This feature should only be used sparingly in critical situations - for - instance when the user would loose data - since popping up modal dialog - boxes is considered quite rude in the web world. Note that there's no way - to customize the content of this dialog box or run any code as a result - of the user's decision. Also note that the user must have interacted with - the site before the dialog box will appear. These are all security measures - to prevent fishing. - - The Dear ImGui HighDPI sample contains example code of how to - implement a 'Really Quit?' dialog box with Dear ImGui (native desktop - platforms only), and for showing the hardwired "Leave Site?" dialog box - when running on the web platform: - - https://floooh.github.io/sokol-html5/wasm/imgui-highdpi-sapp.html - - FULLSCREEN - ========== - If the sapp_desc.fullscreen flag is true, sokol-app will try to create - a fullscreen window on platforms with a 'proper' window system - (mobile devices will always use fullscreen). The implementation details - depend on the target platform, in general sokol-app will use a - 'soft approach' which doesn't interfere too much with the platform's - window system (for instance borderless fullscreen window instead of - a 'real' fullscreen mode). Such details might change over time - as sokol-app is adapted for different needs. - - The most important effect of fullscreen mode to keep in mind is that - the requested canvas width and height will be ignored for the initial - window size, calling sapp_width() and sapp_height() will instead return - the resolution of the fullscreen canvas (however the provided size - might still be used for the non-fullscreen window, in case the user can - switch back from fullscreen- to windowed-mode). - - To toggle fullscreen mode programmatically, call sapp_toggle_fullscreen(). - - To check if the application window is currently in fullscreen mode, - call sapp_is_fullscreen(). - - WINDOW ICON SUPPORT - =================== - Some sokol_app.h backends allow to change the window icon programmatically: - - - on Win32: the small icon in the window's title bar, and the - bigger icon in the task bar - - on Linux: highly dependent on the used window manager, but usually - the window's title bar icon and/or the task bar icon - - on HTML5: the favicon shown in the page's browser tab - - NOTE that it is not possible to set the actual application icon which is - displayed by the operating system on the desktop or 'home screen'. Those - icons must be provided 'traditionally' through operating-system-specific - resources which are associated with the application (sokol_app.h might - later support setting the window icon from platform specific resource data - though). - - There are two ways to set the window icon: - - - at application start in the sokol_main() function by initializing - the sapp_desc.icon nested struct - - or later by calling the function sapp_set_icon() - - As a convenient shortcut, sokol_app.h comes with a builtin default-icon - (a rainbow-colored 'S', which at least looks a bit better than the Windows - default icon for applications), which can be activated like this: - - At startup in sokol_main(): - - sapp_desc sokol_main(...) { - return (sapp_desc){ - ... - icon.sokol_default = true - }; - } - - Or later by calling: - - sapp_set_icon(&(sapp_icon_desc){ .sokol_default = true }); - - NOTE that a completely zero-initialized sapp_icon_desc struct will not - update the window icon in any way. This is an 'escape hatch' so that you - can handle the window icon update yourself (or if you do this already, - sokol_app.h won't get in your way, in this case just leave the - sapp_desc.icon struct zero-initialized). - - Providing your own icon images works exactly like in GLFW (down to the - data format): - - You provide one or more 'candidate images' in different sizes, and the - sokol_app.h platform backends pick the best match for the specific backend - and icon type. - - For each candidate image, you need to provide: - - - the width in pixels - - the height in pixels - - and the actual pixel data in RGBA8 pixel format (e.g. 0xFFCC8844 - on a little-endian CPU means: alpha=0xFF, blue=0xCC, green=0x88, red=0x44) - - For instance, if you have 3 candidate images (small, medium, big) of - sizes 16x16, 32x32 and 64x64 the corresponding sapp_icon_desc struct is setup - like this: - - // the actual pixel data (RGBA8, origin top-left) - const uint32_t small[16][16] = { ... }; - const uint32_t medium[32][32] = { ... }; - const uint32_t big[64][64] = { ... }; - - const sapp_icon_desc icon_desc = { - .images = { - { .width = 16, .height = 16, .pixels = SAPP_RANGE(small) }, - { .width = 32, .height = 32, .pixels = SAPP_RANGE(medium) }, - // ...or without the SAPP_RANGE helper macro: - { .width = 64, .height = 64, .pixels = { .ptr=big, .size=sizeof(big) } } - } - }; - - An sapp_icon_desc struct initialized like this can then either be applied - at application start in sokol_main: - - sapp_desc sokol_main(...) { - return (sapp_desc){ - ... - icon = icon_desc - }; - } - - ...or later by calling sapp_set_icon(): - - sapp_set_icon(&icon_desc); - - Some window icon caveats: - - - once the window icon has been updated, there's no way to go back to - the platform's default icon, this is because some platforms (Linux - and HTML5) don't switch the icon visual back to the default even if - the custom icon is deleted or removed - - on HTML5, if the sokol_app.h icon doesn't show up in the browser - tab, check that there's no traditional favicon 'link' element - is defined in the page's index.html, sokol_app.h will only - append a new favicon link element, but not delete any manually - defined favicon in the page - - For an example and test of the window icon feature, check out the - 'icon-sapp' sample on the sokol-samples git repository. - - ONSCREEN KEYBOARD - ================= - On some platforms which don't provide a physical keyboard, sokol-app - can display the platform's integrated onscreen keyboard for text - input. To request that the onscreen keyboard is shown, call - - sapp_show_keyboard(true); - - Likewise, to hide the keyboard call: - - sapp_show_keyboard(false); - - Note that onscreen keyboard functionality is no longer supported - on the browser platform (the previous hacks and workarounds to make browser - keyboards work for on web applications that don't use HTML UIs - never really worked across browsers). - - INPUT EVENT BUBBLING ON THE WEB PLATFORM - ======================================== - By default, input event bubbling on the web platform is configured in - a way that makes the most sense for 'full-canvas' apps that cover the - entire browser client window area: - - - mouse, touch and wheel events do not bubble up, this prevents various - ugly side events, like: - - HTML text overlays being selected on double- or triple-click into - the canvas - - 'scroll bumping' even when the canvas covers the entire client area - - key_up/down events for 'character keys' *do* bubble up (otherwise - the browser will not generate UNICODE character events) - - all other key events *do not* bubble up by default (this prevents side effects - like F1 opening help, or F7 starting 'caret browsing') - - character events do no bubble up (although I haven't noticed any side effects - otherwise) - - Event bubbling can be enabled for input event categories during initialization - in the sapp_desc struct: - - sapp_desc sokol_main(int argc, char* argv[]) { - return (sapp_desc){ - //... - .html5_bubble_mouse_events = true, - .html5_bubble_touch_events = true, - .html5_bubble_wheel_events = true, - .html5_bubble_key_events = true, - .html5_bubble_char_events = true, - }; - } - - This basically opens the floodgates lets *all* input events bubble up to the browser. - To prevent individual events from bubbling, call sapp_consume_event() from within - the sokol_app.h event callback. - - OPTIONAL: DON'T HIJACK main() (#define SOKOL_NO_ENTRY) - ====================================================== - NOTE: SOKOL_NO_ENTRY and sapp_run() is currently not supported on Android. - - In its default configuration, sokol_app.h "hijacks" the platform's - standard main() function. This was done because different platforms - have different entry point conventions which are not compatible with - C's main() (for instance WinMain on Windows has completely different - arguments). However, this "main hijacking" posed a problem for - usage scenarios like integrating sokol_app.h with other languages than - C or C++, so an alternative SOKOL_NO_ENTRY mode has been added - in which the user code provides the platform's main function: - - - define SOKOL_NO_ENTRY before including the sokol_app.h implementation - - do *not* provide a sokol_main() function - - instead provide the standard main() function of the platform - - from the main function, call the function ```sapp_run()``` which - takes a pointer to an ```sapp_desc``` structure. - - from here on```sapp_run()``` takes over control and calls the provided - init-, frame-, event- and cleanup-callbacks just like in the default model. - - sapp_run() behaves differently across platforms: - - - on some platforms, sapp_run() will return when the application quits - - on other platforms, sapp_run() will never return, even when the - application quits (the operating system is free to simply terminate - the application at any time) - - on Emscripten specifically, sapp_run() will return immediately while - the frame callback keeps being called - - This different behaviour of sapp_run() essentially means that there shouldn't - be any code *after* sapp_run(), because that may either never be called, or in - case of Emscripten will be called at an unexpected time (at application start). - - An application also should not depend on the cleanup-callback being called - when cross-platform compatibility is required. - - Since sapp_run() returns immediately on Emscripten you shouldn't activate - the 'EXIT_RUNTIME' linker option (this is disabled by default when compiling - for the browser target), since the C/C++ exit runtime would be called immediately at - application start, causing any global objects to be destroyed and global - variables to be zeroed. - - WINDOWS CONSOLE OUTPUT - ====================== - On Windows, regular windowed applications don't show any stdout/stderr text - output, which can be a bit of a hassle for printf() debugging or generally - logging text to the console. Also, console output by default uses a local - codepage setting and thus international UTF-8 encoded text is printed - as garbage. - - To help with these issues, sokol_app.h can be configured at startup - via the following Windows-specific sapp_desc flags: - - sapp_desc.win32_console_utf8 (default: false) - When set to true, the output console codepage will be switched - to UTF-8 (and restored to the original codepage on exit) - - sapp_desc.win32_console_attach (default: false) - When set to true, stdout and stderr will be attached to the - console of the parent process (if the parent process actually - has a console). This means that if the application was started - in a command line window, stdout and stderr output will be printed - to the terminal, just like a regular command line program. But if - the application is started via double-click, it will behave like - a regular UI application, and stdout/stderr will not be visible. - - sapp_desc.win32_console_create (default: false) - When set to true, a new console window will be created and - stdout/stderr will be redirected to that console window. It - doesn't matter if the application is started from the command - line or via double-click. - - 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); - } - - sapp_desc sokol_main(int argc, char* argv[]) { - return (sapp_desc){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ..., - } - }; - } - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_app.h - itself though, not any allocations in OS libraries. - - - 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" - - sapp_desc sokol_main(int argc, char* argv[]) { - return (sapp_desc) { - ... - .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. 'sapp' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SAPP_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_app.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-app like this: - - sapp_desc sokol_main(int argc, char* argv[]) { - return (sapp_desc) { - ... - .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. - - - TEMP NOTE DUMP - ============== - - sapp_desc needs a bool whether to initialize depth-stencil surface - - the Android implementation calls cleanup_cb() and destroys the egl context in onDestroy - at the latest but should do it earlier, in onStop, as an app is "killable" after onStop - on Android Honeycomb and later (it can't be done at the moment as the app may be started - again after onStop and the sokol lifecycle does not yet handle context teardown/bringup) - - - 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. -*/ -#define SOKOL_APP_INCLUDED (1) -#include // size_t -#include -#include - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_APP_API_DECL) -#define SOKOL_APP_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_APP_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_APP_IMPL) -#define SOKOL_APP_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_APP_API_DECL __declspec(dllimport) -#else -#define SOKOL_APP_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* misc constants */ -enum { - SAPP_MAX_TOUCHPOINTS = 8, - SAPP_MAX_MOUSEBUTTONS = 3, - SAPP_MAX_KEYCODES = 512, - SAPP_MAX_ICONIMAGES = 8, -}; - -/* - sapp_event_type - - The type of event that's passed to the event handler callback - in the sapp_event.type field. These are not just "traditional" - input events, but also notify the application about state changes - or other user-invoked actions. -*/ -typedef enum sapp_event_type { - SAPP_EVENTTYPE_INVALID, - SAPP_EVENTTYPE_KEY_DOWN, - SAPP_EVENTTYPE_KEY_UP, - SAPP_EVENTTYPE_CHAR, - SAPP_EVENTTYPE_MOUSE_DOWN, - SAPP_EVENTTYPE_MOUSE_UP, - SAPP_EVENTTYPE_MOUSE_SCROLL, - SAPP_EVENTTYPE_MOUSE_MOVE, - SAPP_EVENTTYPE_MOUSE_ENTER, - SAPP_EVENTTYPE_MOUSE_LEAVE, - SAPP_EVENTTYPE_TOUCHES_BEGAN, - SAPP_EVENTTYPE_TOUCHES_MOVED, - SAPP_EVENTTYPE_TOUCHES_ENDED, - SAPP_EVENTTYPE_TOUCHES_CANCELLED, - SAPP_EVENTTYPE_RESIZED, - SAPP_EVENTTYPE_ICONIFIED, - SAPP_EVENTTYPE_RESTORED, - SAPP_EVENTTYPE_FOCUSED, - SAPP_EVENTTYPE_UNFOCUSED, - SAPP_EVENTTYPE_SUSPENDED, - SAPP_EVENTTYPE_RESUMED, - SAPP_EVENTTYPE_QUIT_REQUESTED, - SAPP_EVENTTYPE_CLIPBOARD_PASTED, - SAPP_EVENTTYPE_FILES_DROPPED, - _SAPP_EVENTTYPE_NUM, - _SAPP_EVENTTYPE_FORCE_U32 = 0x7FFFFFFF -} sapp_event_type; - -/* - sapp_keycode - - The 'virtual keycode' of a KEY_DOWN or KEY_UP event in the - struct field sapp_event.key_code. - - Note that the keycode values are identical with GLFW. -*/ -typedef enum sapp_keycode { - SAPP_KEYCODE_INVALID = 0, - SAPP_KEYCODE_SPACE = 32, - SAPP_KEYCODE_APOSTROPHE = 39, /* ' */ - SAPP_KEYCODE_COMMA = 44, /* , */ - SAPP_KEYCODE_MINUS = 45, /* - */ - SAPP_KEYCODE_PERIOD = 46, /* . */ - SAPP_KEYCODE_SLASH = 47, /* / */ - SAPP_KEYCODE_0 = 48, - SAPP_KEYCODE_1 = 49, - SAPP_KEYCODE_2 = 50, - SAPP_KEYCODE_3 = 51, - SAPP_KEYCODE_4 = 52, - SAPP_KEYCODE_5 = 53, - SAPP_KEYCODE_6 = 54, - SAPP_KEYCODE_7 = 55, - SAPP_KEYCODE_8 = 56, - SAPP_KEYCODE_9 = 57, - SAPP_KEYCODE_SEMICOLON = 59, /* ; */ - SAPP_KEYCODE_EQUAL = 61, /* = */ - SAPP_KEYCODE_A = 65, - SAPP_KEYCODE_B = 66, - SAPP_KEYCODE_C = 67, - SAPP_KEYCODE_D = 68, - SAPP_KEYCODE_E = 69, - SAPP_KEYCODE_F = 70, - SAPP_KEYCODE_G = 71, - SAPP_KEYCODE_H = 72, - SAPP_KEYCODE_I = 73, - SAPP_KEYCODE_J = 74, - SAPP_KEYCODE_K = 75, - SAPP_KEYCODE_L = 76, - SAPP_KEYCODE_M = 77, - SAPP_KEYCODE_N = 78, - SAPP_KEYCODE_O = 79, - SAPP_KEYCODE_P = 80, - SAPP_KEYCODE_Q = 81, - SAPP_KEYCODE_R = 82, - SAPP_KEYCODE_S = 83, - SAPP_KEYCODE_T = 84, - SAPP_KEYCODE_U = 85, - SAPP_KEYCODE_V = 86, - SAPP_KEYCODE_W = 87, - SAPP_KEYCODE_X = 88, - SAPP_KEYCODE_Y = 89, - SAPP_KEYCODE_Z = 90, - SAPP_KEYCODE_LEFT_BRACKET = 91, /* [ */ - SAPP_KEYCODE_BACKSLASH = 92, /* \ */ - SAPP_KEYCODE_RIGHT_BRACKET = 93, /* ] */ - SAPP_KEYCODE_GRAVE_ACCENT = 96, /* ` */ - SAPP_KEYCODE_WORLD_1 = 161, /* non-US #1 */ - SAPP_KEYCODE_WORLD_2 = 162, /* non-US #2 */ - SAPP_KEYCODE_ESCAPE = 256, - SAPP_KEYCODE_ENTER = 257, - SAPP_KEYCODE_TAB = 258, - SAPP_KEYCODE_BACKSPACE = 259, - SAPP_KEYCODE_INSERT = 260, - SAPP_KEYCODE_DELETE = 261, - SAPP_KEYCODE_RIGHT = 262, - SAPP_KEYCODE_LEFT = 263, - SAPP_KEYCODE_DOWN = 264, - SAPP_KEYCODE_UP = 265, - SAPP_KEYCODE_PAGE_UP = 266, - SAPP_KEYCODE_PAGE_DOWN = 267, - SAPP_KEYCODE_HOME = 268, - SAPP_KEYCODE_END = 269, - SAPP_KEYCODE_CAPS_LOCK = 280, - SAPP_KEYCODE_SCROLL_LOCK = 281, - SAPP_KEYCODE_NUM_LOCK = 282, - SAPP_KEYCODE_PRINT_SCREEN = 283, - SAPP_KEYCODE_PAUSE = 284, - SAPP_KEYCODE_F1 = 290, - SAPP_KEYCODE_F2 = 291, - SAPP_KEYCODE_F3 = 292, - SAPP_KEYCODE_F4 = 293, - SAPP_KEYCODE_F5 = 294, - SAPP_KEYCODE_F6 = 295, - SAPP_KEYCODE_F7 = 296, - SAPP_KEYCODE_F8 = 297, - SAPP_KEYCODE_F9 = 298, - SAPP_KEYCODE_F10 = 299, - SAPP_KEYCODE_F11 = 300, - SAPP_KEYCODE_F12 = 301, - SAPP_KEYCODE_F13 = 302, - SAPP_KEYCODE_F14 = 303, - SAPP_KEYCODE_F15 = 304, - SAPP_KEYCODE_F16 = 305, - SAPP_KEYCODE_F17 = 306, - SAPP_KEYCODE_F18 = 307, - SAPP_KEYCODE_F19 = 308, - SAPP_KEYCODE_F20 = 309, - SAPP_KEYCODE_F21 = 310, - SAPP_KEYCODE_F22 = 311, - SAPP_KEYCODE_F23 = 312, - SAPP_KEYCODE_F24 = 313, - SAPP_KEYCODE_F25 = 314, - SAPP_KEYCODE_KP_0 = 320, - SAPP_KEYCODE_KP_1 = 321, - SAPP_KEYCODE_KP_2 = 322, - SAPP_KEYCODE_KP_3 = 323, - SAPP_KEYCODE_KP_4 = 324, - SAPP_KEYCODE_KP_5 = 325, - SAPP_KEYCODE_KP_6 = 326, - SAPP_KEYCODE_KP_7 = 327, - SAPP_KEYCODE_KP_8 = 328, - SAPP_KEYCODE_KP_9 = 329, - SAPP_KEYCODE_KP_DECIMAL = 330, - SAPP_KEYCODE_KP_DIVIDE = 331, - SAPP_KEYCODE_KP_MULTIPLY = 332, - SAPP_KEYCODE_KP_SUBTRACT = 333, - SAPP_KEYCODE_KP_ADD = 334, - SAPP_KEYCODE_KP_ENTER = 335, - SAPP_KEYCODE_KP_EQUAL = 336, - SAPP_KEYCODE_LEFT_SHIFT = 340, - SAPP_KEYCODE_LEFT_CONTROL = 341, - SAPP_KEYCODE_LEFT_ALT = 342, - SAPP_KEYCODE_LEFT_SUPER = 343, - SAPP_KEYCODE_RIGHT_SHIFT = 344, - SAPP_KEYCODE_RIGHT_CONTROL = 345, - SAPP_KEYCODE_RIGHT_ALT = 346, - SAPP_KEYCODE_RIGHT_SUPER = 347, - SAPP_KEYCODE_MENU = 348, -} sapp_keycode; - -/* - Android specific 'tool type' enum for touch events. This lets the - application check what type of input device was used for - touch events. - - NOTE: the values must remain in sync with the corresponding - Android SDK type, so don't change those. - - See https://developer.android.com/reference/android/view/MotionEvent#TOOL_TYPE_UNKNOWN -*/ -typedef enum sapp_android_tooltype { - SAPP_ANDROIDTOOLTYPE_UNKNOWN = 0, // TOOL_TYPE_UNKNOWN - SAPP_ANDROIDTOOLTYPE_FINGER = 1, // TOOL_TYPE_FINGER - SAPP_ANDROIDTOOLTYPE_STYLUS = 2, // TOOL_TYPE_STYLUS - SAPP_ANDROIDTOOLTYPE_MOUSE = 3, // TOOL_TYPE_MOUSE -} sapp_android_tooltype; - -/* - sapp_touchpoint - - Describes a single touchpoint in a multitouch event (TOUCHES_BEGAN, - TOUCHES_MOVED, TOUCHES_ENDED). - - Touch points are stored in the nested array sapp_event.touches[], - and the number of touches is stored in sapp_event.num_touches. -*/ -typedef struct sapp_touchpoint { - uintptr_t identifier; - float pos_x; - float pos_y; - sapp_android_tooltype android_tooltype; // only valid on Android - bool changed; -} sapp_touchpoint; - -/* - sapp_mousebutton - - The currently pressed mouse button in the events MOUSE_DOWN - and MOUSE_UP, stored in the struct field sapp_event.mouse_button. -*/ -typedef enum sapp_mousebutton { - SAPP_MOUSEBUTTON_LEFT = 0x0, - SAPP_MOUSEBUTTON_RIGHT = 0x1, - SAPP_MOUSEBUTTON_MIDDLE = 0x2, - SAPP_MOUSEBUTTON_INVALID = 0x100, -} sapp_mousebutton; - -/* - These are currently pressed modifier keys (and mouse buttons) which are - passed in the event struct field sapp_event.modifiers. -*/ -enum { - SAPP_MODIFIER_SHIFT = 0x1, // left or right shift key - SAPP_MODIFIER_CTRL = 0x2, // left or right control key - SAPP_MODIFIER_ALT = 0x4, // left or right alt key - SAPP_MODIFIER_SUPER = 0x8, // left or right 'super' key - SAPP_MODIFIER_LMB = 0x100, // left mouse button - SAPP_MODIFIER_RMB = 0x200, // right mouse button - SAPP_MODIFIER_MMB = 0x400, // middle mouse button -}; - -/* - sapp_event - - This is an all-in-one event struct passed to the event handler - user callback function. Note that it depends on the event - type what struct fields actually contain useful values, so you - should first check the event type before reading other struct - fields. -*/ -typedef struct sapp_event { - uint64_t frame_count; // current frame counter, always valid, useful for checking if two events were issued in the same frame - sapp_event_type type; // the event type, always valid - sapp_keycode key_code; // the virtual key code, only valid in KEY_UP, KEY_DOWN - uint32_t char_code; // the UTF-32 character code, only valid in CHAR events - bool key_repeat; // true if this is a key-repeat event, valid in KEY_UP, KEY_DOWN and CHAR - uint32_t modifiers; // current modifier keys, valid in all key-, char- and mouse-events - sapp_mousebutton mouse_button; // mouse button that was pressed or released, valid in MOUSE_DOWN, MOUSE_UP - float mouse_x; // current horizontal mouse position in pixels, always valid except during mouse lock - float mouse_y; // current vertical mouse position in pixels, always valid except during mouse lock - float mouse_dx; // relative horizontal mouse movement since last frame, always valid - float mouse_dy; // relative vertical mouse movement since last frame, always valid - float scroll_x; // horizontal mouse wheel scroll distance, valid in MOUSE_SCROLL events - float scroll_y; // vertical mouse wheel scroll distance, valid in MOUSE_SCROLL events - int num_touches; // number of valid items in the touches[] array - sapp_touchpoint touches[SAPP_MAX_TOUCHPOINTS]; // current touch points, valid in TOUCHES_BEGIN, TOUCHES_MOVED, TOUCHES_ENDED - int window_width; // current window- and framebuffer sizes in pixels, always valid - int window_height; - int framebuffer_width; // = window_width * dpi_scale - int framebuffer_height; // = window_height * dpi_scale -} sapp_event; - -/* - sg_range - - A general pointer/size-pair struct and constructor macros for passing binary blobs - into sokol_app.h. -*/ -typedef struct sapp_range { - const void* ptr; - size_t size; -} sapp_range; -// disabling this for every includer isn't great, but the warnings are also quite pointless -#if defined(_MSC_VER) -#pragma warning(disable:4221) /* /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' */ -#pragma warning(disable:4204) /* VS2015: nonstandard extension used: non-constant aggregate initializer */ -#endif -#if defined(__cplusplus) -#define SAPP_RANGE(x) sapp_range{ &x, sizeof(x) } -#else -#define SAPP_RANGE(x) (sapp_range){ &x, sizeof(x) } -#endif - -/* - sapp_image_desc - - This is used to describe image data to sokol_app.h (at first, window - icons, later maybe cursor images). - - Note that the actual image pixel format depends on the use case: - - - window icon pixels are RGBA8 -*/ -typedef struct sapp_image_desc { - int width; - int height; - sapp_range pixels; -} sapp_image_desc; - -/* - sapp_icon_desc - - An icon description structure for use in sapp_desc.icon and - sapp_set_icon(). - - When setting a custom image, the application can provide a number of - candidates differing in size, and sokol_app.h will pick the image(s) - closest to the size expected by the platform's window system. - - To set sokol-app's default icon, set .sokol_default to true. - - Otherwise provide candidate images of different sizes in the - images[] array. - - If both the sokol_default flag is set to true, any image candidates - will be ignored and the sokol_app.h default icon will be set. -*/ -typedef struct sapp_icon_desc { - bool sokol_default; - sapp_image_desc images[SAPP_MAX_ICONIMAGES]; -} sapp_icon_desc; - -/* - sapp_allocator - - Used in sapp_desc to provide custom memory-alloc and -free functions - to sokol_app.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct sapp_allocator { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sapp_allocator; - -/* - sapp_log_item - - Log items are defined via X-Macros and expanded to an enum - 'sapp_log_item', and in debug mode to corresponding - human readable error messages. -*/ -#define _SAPP_LOG_ITEMS \ - _SAPP_LOGITEM_XMACRO(OK, "Ok") \ - _SAPP_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SAPP_LOGITEM_XMACRO(MACOS_INVALID_NSOPENGL_PROFILE, "macos: invalid NSOpenGLProfile (valid choices are 1.0 and 4.1)") \ - _SAPP_LOGITEM_XMACRO(WIN32_LOAD_OPENGL32_DLL_FAILED, "failed loading opengl32.dll") \ - _SAPP_LOGITEM_XMACRO(WIN32_CREATE_HELPER_WINDOW_FAILED, "failed to create helper window") \ - _SAPP_LOGITEM_XMACRO(WIN32_HELPER_WINDOW_GETDC_FAILED, "failed to get helper window DC") \ - _SAPP_LOGITEM_XMACRO(WIN32_DUMMY_CONTEXT_SET_PIXELFORMAT_FAILED, "failed to set pixel format for dummy GL context") \ - _SAPP_LOGITEM_XMACRO(WIN32_CREATE_DUMMY_CONTEXT_FAILED, "failed to create dummy GL context") \ - _SAPP_LOGITEM_XMACRO(WIN32_DUMMY_CONTEXT_MAKE_CURRENT_FAILED, "failed to make dummy GL context current") \ - _SAPP_LOGITEM_XMACRO(WIN32_GET_PIXELFORMAT_ATTRIB_FAILED, "failed to get WGL pixel format attribute") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_FIND_PIXELFORMAT_FAILED, "failed to find matching WGL pixel format") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_DESCRIBE_PIXELFORMAT_FAILED, "failed to get pixel format descriptor") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_SET_PIXELFORMAT_FAILED, "failed to set selected pixel format") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_ARB_CREATE_CONTEXT_REQUIRED, "ARB_create_context required") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_ARB_CREATE_CONTEXT_PROFILE_REQUIRED, "ARB_create_context_profile required") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_OPENGL_VERSION_NOT_SUPPORTED, "requested OpenGL version not supported by GL driver (ERROR_INVALID_VERSION_ARB)") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_OPENGL_PROFILE_NOT_SUPPORTED, "requested OpenGL profile not support by GL driver (ERROR_INVALID_PROFILE_ARB)") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_INCOMPATIBLE_DEVICE_CONTEXT, "CreateContextAttribsARB failed with ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_CREATE_CONTEXT_ATTRIBS_FAILED_OTHER, "CreateContextAttribsARB failed for other reason") \ - _SAPP_LOGITEM_XMACRO(WIN32_D3D11_CREATE_DEVICE_AND_SWAPCHAIN_WITH_DEBUG_FAILED, "D3D11CreateDeviceAndSwapChain() with D3D11_CREATE_DEVICE_DEBUG failed, retrying without debug flag.") \ - _SAPP_LOGITEM_XMACRO(WIN32_D3D11_GET_IDXGIFACTORY_FAILED, "could not obtain IDXGIFactory object") \ - _SAPP_LOGITEM_XMACRO(WIN32_D3D11_GET_IDXGIADAPTER_FAILED, "could not obtain IDXGIAdapter object") \ - _SAPP_LOGITEM_XMACRO(WIN32_D3D11_QUERY_INTERFACE_IDXGIDEVICE1_FAILED, "could not obtain IDXGIDevice1 interface") \ - _SAPP_LOGITEM_XMACRO(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_LOCK, "RegisterRawInputDevices() failed (on mouse lock)") \ - _SAPP_LOGITEM_XMACRO(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_UNLOCK, "RegisterRawInputDevices() failed (on mouse unlock)") \ - _SAPP_LOGITEM_XMACRO(WIN32_GET_RAW_INPUT_DATA_FAILED, "GetRawInputData() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_LOAD_LIBGL_FAILED, "failed to load libGL") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_LOAD_ENTRY_POINTS_FAILED, "failed to load GLX entry points") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_EXTENSION_NOT_FOUND, "GLX extension not found") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_QUERY_VERSION_FAILED, "failed to query GLX version") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_VERSION_TOO_LOW, "GLX version too low (need at least 1.3)") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_NO_GLXFBCONFIGS, "glXGetFBConfigs() returned no configs") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_NO_SUITABLE_GLXFBCONFIG, "failed to find a suitable GLXFBConfig") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_GET_VISUAL_FROM_FBCONFIG_FAILED, "glXGetVisualFromFBConfig failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_REQUIRED_EXTENSIONS_MISSING, "GLX extensions ARB_create_context and ARB_create_context_profile missing") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_CREATE_CONTEXT_FAILED, "Failed to create GL context via glXCreateContextAttribsARB") \ - _SAPP_LOGITEM_XMACRO(LINUX_GLX_CREATE_WINDOW_FAILED, "glXCreateWindow() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_X11_CREATE_WINDOW_FAILED, "XCreateWindow() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_BIND_OPENGL_API_FAILED, "eglBindAPI(EGL_OPENGL_API) failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_BIND_OPENGL_ES_API_FAILED, "eglBindAPI(EGL_OPENGL_ES_API) failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_GET_DISPLAY_FAILED, "eglGetDisplay() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_INITIALIZE_FAILED, "eglInitialize() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_NO_CONFIGS, "eglChooseConfig() returned no configs") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_NO_NATIVE_VISUAL, "eglGetConfigAttrib() for EGL_NATIVE_VISUAL_ID failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_GET_VISUAL_INFO_FAILED, "XGetVisualInfo() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_CREATE_WINDOW_SURFACE_FAILED, "eglCreateWindowSurface() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_CREATE_CONTEXT_FAILED, "eglCreateContext() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_EGL_MAKE_CURRENT_FAILED, "eglMakeCurrent() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_X11_OPEN_DISPLAY_FAILED, "XOpenDisplay() failed") \ - _SAPP_LOGITEM_XMACRO(LINUX_X11_QUERY_SYSTEM_DPI_FAILED, "failed to query system dpi value, assuming default 96.0") \ - _SAPP_LOGITEM_XMACRO(LINUX_X11_DROPPED_FILE_URI_WRONG_SCHEME, "dropped file URL doesn't start with 'file://'") \ - _SAPP_LOGITEM_XMACRO(ANDROID_UNSUPPORTED_INPUT_EVENT_INPUT_CB, "unsupported input event encountered in _sapp_android_input_cb()") \ - _SAPP_LOGITEM_XMACRO(ANDROID_UNSUPPORTED_INPUT_EVENT_MAIN_CB, "unsupported input event encountered in _sapp_android_main_cb()") \ - _SAPP_LOGITEM_XMACRO(ANDROID_READ_MSG_FAILED, "failed to read message in _sapp_android_main_cb()") \ - _SAPP_LOGITEM_XMACRO(ANDROID_WRITE_MSG_FAILED, "failed to write message in _sapp_android_msg") \ - _SAPP_LOGITEM_XMACRO(ANDROID_MSG_CREATE, "MSG_CREATE") \ - _SAPP_LOGITEM_XMACRO(ANDROID_MSG_RESUME, "MSG_RESUME") \ - _SAPP_LOGITEM_XMACRO(ANDROID_MSG_PAUSE, "MSG_PAUSE") \ - _SAPP_LOGITEM_XMACRO(ANDROID_MSG_FOCUS, "MSG_FOCUS") \ - _SAPP_LOGITEM_XMACRO(ANDROID_MSG_NO_FOCUS, "MSG_NO_FOCUS") \ - _SAPP_LOGITEM_XMACRO(ANDROID_MSG_SET_NATIVE_WINDOW, "MSG_SET_NATIVE_WINDOW") \ - _SAPP_LOGITEM_XMACRO(ANDROID_MSG_SET_INPUT_QUEUE, "MSG_SET_INPUT_QUEUE") \ - _SAPP_LOGITEM_XMACRO(ANDROID_MSG_DESTROY, "MSG_DESTROY") \ - _SAPP_LOGITEM_XMACRO(ANDROID_UNKNOWN_MSG, "unknown msg type received") \ - _SAPP_LOGITEM_XMACRO(ANDROID_LOOP_THREAD_STARTED, "loop thread started") \ - _SAPP_LOGITEM_XMACRO(ANDROID_LOOP_THREAD_DONE, "loop thread done") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONSTART, "NativeActivity onStart()") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONRESUME, "NativeActivity onResume") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONSAVEINSTANCESTATE, "NativeActivity onSaveInstanceState") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONWINDOWFOCUSCHANGED, "NativeActivity onWindowFocusChanged") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONPAUSE, "NativeActivity onPause") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONSTOP, "NativeActivity onStop()") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONNATIVEWINDOWCREATED, "NativeActivity onNativeWindowCreated") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONNATIVEWINDOWDESTROYED, "NativeActivity onNativeWindowDestroyed") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONINPUTQUEUECREATED, "NativeActivity onInputQueueCreated") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONINPUTQUEUEDESTROYED, "NativeActivity onInputQueueDestroyed") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONCONFIGURATIONCHANGED, "NativeActivity onConfigurationChanged") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONLOWMEMORY, "NativeActivity onLowMemory") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONDESTROY, "NativeActivity onDestroy") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_DONE, "NativeActivity done") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONCREATE, "NativeActivity onCreate") \ - _SAPP_LOGITEM_XMACRO(ANDROID_CREATE_THREAD_PIPE_FAILED, "failed to create thread pipe") \ - _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_CREATE_SUCCESS, "NativeActivity successfully created") \ - _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_SURFACE_FAILED, "wgpu: failed to create surface for swapchain") \ - _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_SWAPCHAIN_FAILED, "wgpu: failed to create swapchain object") \ - _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_DEPTH_STENCIL_TEXTURE_FAILED, "wgpu: failed to create depth-stencil texture for swapchain") \ - _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_DEPTH_STENCIL_VIEW_FAILED, "wgpu: failed to create view object for swapchain depth-stencil texture") \ - _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_MSAA_TEXTURE_FAILED, "wgpu: failed to create msaa texture for swapchain") \ - _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_MSAA_VIEW_FAILED, "wgpu: failed to create view object for swapchain msaa texture") \ - _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_DEVICE_STATUS_ERROR, "wgpu: requesting device failed with status 'error'") \ - _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_DEVICE_STATUS_UNKNOWN, "wgpu: requesting device failed with status 'unknown'") \ - _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_ADAPTER_STATUS_UNAVAILABLE, "wgpu: requesting adapter failed with 'unavailable'") \ - _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_ADAPTER_STATUS_ERROR, "wgpu: requesting adapter failed with status 'error'") \ - _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_ADAPTER_STATUS_UNKNOWN, "wgpu: requesting adapter failed with status 'unknown'") \ - _SAPP_LOGITEM_XMACRO(WGPU_CREATE_INSTANCE_FAILED, "wgpu: failed to create instance") \ - _SAPP_LOGITEM_XMACRO(IMAGE_DATA_SIZE_MISMATCH, "image data size mismatch (must be width*height*4 bytes)") \ - _SAPP_LOGITEM_XMACRO(DROPPED_FILE_PATH_TOO_LONG, "dropped file path too long (sapp_desc.max_dropped_filed_path_length)") \ - _SAPP_LOGITEM_XMACRO(CLIPBOARD_STRING_TOO_BIG, "clipboard string didn't fit into clipboard buffer") \ - -#define _SAPP_LOGITEM_XMACRO(item,msg) SAPP_LOGITEM_##item, -typedef enum sapp_log_item { - _SAPP_LOG_ITEMS -} sapp_log_item; -#undef _SAPP_LOGITEM_XMACRO - -/* - sapp_logger - - Used in sapp_desc to provide a logging function. Please be aware that - without logging function, sokol-app will be completely silent, e.g. it will - not report errors or warnings. For maximum error verbosity, compile in - debug mode (e.g. NDEBUG *not* defined) and install a logger (for instance - the standard logging function from sokol_log.h). -*/ -typedef struct sapp_logger { - void (*func)( - const char* tag, // always "sapp" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SAPP_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_app.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} sapp_logger; - -typedef struct sapp_desc { - void (*init_cb)(void); // these are the user-provided callbacks without user data - void (*frame_cb)(void); - void (*cleanup_cb)(void); - void (*event_cb)(const sapp_event*); - - void* user_data; // these are the user-provided callbacks with user data - void (*init_userdata_cb)(void*); - void (*frame_userdata_cb)(void*); - void (*cleanup_userdata_cb)(void*); - void (*event_userdata_cb)(const sapp_event*, void*); - - int width; // the preferred width of the window / canvas - int height; // the preferred height of the window / canvas - int sample_count; // MSAA sample count - int swap_interval; // the preferred swap interval (ignored on some platforms) - bool high_dpi; // whether the rendering canvas is full-resolution on HighDPI displays - bool fullscreen; // whether the window should be created in fullscreen mode - bool alpha; // whether the framebuffer should have an alpha channel (ignored on some platforms) - const char* window_title; // the window title as UTF-8 encoded string - bool enable_clipboard; // enable clipboard access, default is false - int clipboard_size; // max size of clipboard content in bytes - bool enable_dragndrop; // enable file dropping (drag'n'drop), default is false - int max_dropped_files; // max number of dropped files to process (default: 1) - int max_dropped_file_path_length; // max length in bytes of a dropped UTF-8 file path (default: 2048) - sapp_icon_desc icon; // the initial window icon to set - sapp_allocator allocator; // optional memory allocation overrides (default: malloc/free) - sapp_logger logger; // logging callback override (default: NO LOGGING!) - - // backend-specific options - int gl_major_version; // override GL major and minor version (the default GL version is 4.1 on macOS, 4.3 elsewhere) - int gl_minor_version; - bool win32_console_utf8; // if true, set the output console codepage to UTF-8 - bool win32_console_create; // if true, attach stdout/stderr to a new console window - bool win32_console_attach; // if true, attach stdout/stderr to parent process - const char* html5_canvas_name; // the name (id) of the HTML5 canvas element, default is "canvas" - bool html5_canvas_resize; // if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked - bool html5_preserve_drawing_buffer; // HTML5 only: whether to preserve default framebuffer content between frames - bool html5_premultiplied_alpha; // HTML5 only: whether the rendered pixels use premultiplied alpha convention - bool html5_ask_leave_site; // initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) - bool html5_bubble_mouse_events; // if true, mouse events will bubble up to the web page - bool html5_bubble_touch_events; // same for touch events - bool html5_bubble_wheel_events; // same for wheel events - bool html5_bubble_key_events; // if true, bubble up *all* key events to browser, not just key events that represent characters - bool html5_bubble_char_events; // if true, bubble up character events to browser - bool html5_use_emsc_set_main_loop; // if true, use emscripten_set_main_loop() instead of emscripten_request_animation_frame_loop() - bool html5_emsc_set_main_loop_simulate_infinite_loop; // this will be passed as the simulate_infinite_loop arg to emscripten_set_main_loop() - bool ios_keyboard_resizes_canvas; // if true, showing the iOS keyboard shrinks the canvas -} sapp_desc; - -/* HTML5 specific: request and response structs for - asynchronously loading dropped-file content. -*/ -typedef enum sapp_html5_fetch_error { - SAPP_HTML5_FETCH_ERROR_NO_ERROR, - SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL, - SAPP_HTML5_FETCH_ERROR_OTHER, -} sapp_html5_fetch_error; - -typedef struct sapp_html5_fetch_response { - bool succeeded; // true if the loading operation has succeeded - sapp_html5_fetch_error error_code; - int file_index; // index of the dropped file (0..sapp_get_num_dropped_filed()-1) - sapp_range data; // pointer and size of the fetched data (data.ptr == buffer.ptr, data.size <= buffer.size) - sapp_range buffer; // the user-provided buffer ptr/size pair (buffer.ptr == data.ptr, buffer.size >= data.size) - void* user_data; // user-provided user data pointer -} sapp_html5_fetch_response; - -typedef struct sapp_html5_fetch_request { - int dropped_file_index; // 0..sapp_get_num_dropped_files()-1 - void (*callback)(const sapp_html5_fetch_response*); // response callback function pointer (required) - sapp_range buffer; // ptr/size of a memory buffer to load the data into - void* user_data; // optional userdata pointer -} sapp_html5_fetch_request; - -/* - sapp_mouse_cursor - - Predefined cursor image definitions, set with sapp_set_mouse_cursor(sapp_mouse_cursor cursor) -*/ -typedef enum sapp_mouse_cursor { - SAPP_MOUSECURSOR_DEFAULT = 0, // equivalent with system default cursor - SAPP_MOUSECURSOR_ARROW, - SAPP_MOUSECURSOR_IBEAM, - SAPP_MOUSECURSOR_CROSSHAIR, - SAPP_MOUSECURSOR_POINTING_HAND, - SAPP_MOUSECURSOR_RESIZE_EW, - SAPP_MOUSECURSOR_RESIZE_NS, - SAPP_MOUSECURSOR_RESIZE_NWSE, - SAPP_MOUSECURSOR_RESIZE_NESW, - SAPP_MOUSECURSOR_RESIZE_ALL, - SAPP_MOUSECURSOR_NOT_ALLOWED, - _SAPP_MOUSECURSOR_NUM, -} sapp_mouse_cursor; - -/* user-provided functions */ -extern sapp_desc sokol_main(int argc, char* argv[]); - -/* returns true after sokol-app has been initialized */ -SOKOL_APP_API_DECL bool sapp_isvalid(void); -/* returns the current framebuffer width in pixels */ -SOKOL_APP_API_DECL int sapp_width(void); -/* same as sapp_width(), but returns float */ -SOKOL_APP_API_DECL float sapp_widthf(void); -/* returns the current framebuffer height in pixels */ -SOKOL_APP_API_DECL int sapp_height(void); -/* same as sapp_height(), but returns float */ -SOKOL_APP_API_DECL float sapp_heightf(void); -/* get default framebuffer color pixel format */ -SOKOL_APP_API_DECL int sapp_color_format(void); -/* get default framebuffer depth pixel format */ -SOKOL_APP_API_DECL int sapp_depth_format(void); -/* get default framebuffer sample count */ -SOKOL_APP_API_DECL int sapp_sample_count(void); -/* returns true when high_dpi was requested and actually running in a high-dpi scenario */ -SOKOL_APP_API_DECL bool sapp_high_dpi(void); -/* returns the dpi scaling factor (window pixels to framebuffer pixels) */ -SOKOL_APP_API_DECL float sapp_dpi_scale(void); -/* show or hide the mobile device onscreen keyboard */ -SOKOL_APP_API_DECL void sapp_show_keyboard(bool show); -/* return true if the mobile device onscreen keyboard is currently shown */ -SOKOL_APP_API_DECL bool sapp_keyboard_shown(void); -/* query fullscreen mode */ -SOKOL_APP_API_DECL bool sapp_is_fullscreen(void); -/* toggle fullscreen mode */ -SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void); -/* show or hide the mouse cursor */ -SOKOL_APP_API_DECL void sapp_show_mouse(bool show); -/* show or hide the mouse cursor */ -SOKOL_APP_API_DECL bool sapp_mouse_shown(void); -/* enable/disable mouse-pointer-lock mode */ -SOKOL_APP_API_DECL void sapp_lock_mouse(bool lock); -/* return true if in mouse-pointer-lock mode (this may toggle a few frames later) */ -SOKOL_APP_API_DECL bool sapp_mouse_locked(void); -/* set mouse cursor type */ -SOKOL_APP_API_DECL void sapp_set_mouse_cursor(sapp_mouse_cursor cursor); -/* get current mouse cursor type */ -SOKOL_APP_API_DECL sapp_mouse_cursor sapp_get_mouse_cursor(void); -/* return the userdata pointer optionally provided in sapp_desc */ -SOKOL_APP_API_DECL void* sapp_userdata(void); -/* return a copy of the sapp_desc structure */ -SOKOL_APP_API_DECL sapp_desc sapp_query_desc(void); -/* initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED) */ -SOKOL_APP_API_DECL void sapp_request_quit(void); -/* cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received) */ -SOKOL_APP_API_DECL void sapp_cancel_quit(void); -/* initiate a "hard quit" (quit application without sending SAPP_EVENTTYPE_QUIT_REQUESTED) */ -SOKOL_APP_API_DECL void sapp_quit(void); -/* call from inside event callback to consume the current event (don't forward to platform) */ -SOKOL_APP_API_DECL void sapp_consume_event(void); -/* get the current frame counter (for comparison with sapp_event.frame_count) */ -SOKOL_APP_API_DECL uint64_t sapp_frame_count(void); -/* get an averaged/smoothed frame duration in seconds */ -SOKOL_APP_API_DECL double sapp_frame_duration(void); -/* write string into clipboard */ -SOKOL_APP_API_DECL void sapp_set_clipboard_string(const char* str); -/* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) */ -SOKOL_APP_API_DECL const char* sapp_get_clipboard_string(void); -/* set the window title (only on desktop platforms) */ -SOKOL_APP_API_DECL void sapp_set_window_title(const char* str); -/* set the window icon (only on Windows and Linux) */ -SOKOL_APP_API_DECL void sapp_set_icon(const sapp_icon_desc* icon_desc); -/* gets the total number of dropped files (after an SAPP_EVENTTYPE_FILES_DROPPED event) */ -SOKOL_APP_API_DECL int sapp_get_num_dropped_files(void); -/* gets the dropped file paths */ -SOKOL_APP_API_DECL const char* sapp_get_dropped_file_path(int index); - -/* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ -SOKOL_APP_API_DECL void sapp_run(const sapp_desc* desc); - -/* EGL: get EGLDisplay object */ -SOKOL_APP_API_DECL const void* sapp_egl_get_display(void); -/* EGL: get EGLContext object */ -SOKOL_APP_API_DECL const void* sapp_egl_get_context(void); - -/* HTML5: enable or disable the hardwired "Leave Site?" dialog box */ -SOKOL_APP_API_DECL void sapp_html5_ask_leave_site(bool ask); -/* HTML5: get byte size of a dropped file */ -SOKOL_APP_API_DECL uint32_t sapp_html5_get_dropped_file_size(int index); -/* HTML5: asynchronously load the content of a dropped file */ -SOKOL_APP_API_DECL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request); - -/* Metal: get bridged pointer to Metal device object */ -SOKOL_APP_API_DECL const void* sapp_metal_get_device(void); -/* Metal: get bridged pointer to MTKView's current drawable of type CAMetalDrawable */ -SOKOL_APP_API_DECL const void* sapp_metal_get_current_drawable(void); -/* Metal: get bridged pointer to MTKView's depth-stencil texture of type MTLTexture */ -SOKOL_APP_API_DECL const void* sapp_metal_get_depth_stencil_texture(void); -/* Metal: get bridged pointer to MTKView's msaa-color-texture of type MTLTexture (may be null) */ -SOKOL_APP_API_DECL const void* sapp_metal_get_msaa_color_texture(void); -/* macOS: get bridged pointer to macOS NSWindow */ -SOKOL_APP_API_DECL const void* sapp_macos_get_window(void); -/* iOS: get bridged pointer to iOS UIWindow */ -SOKOL_APP_API_DECL const void* sapp_ios_get_window(void); - -/* D3D11: get pointer to ID3D11Device object */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_device(void); -/* D3D11: get pointer to ID3D11DeviceContext object */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_device_context(void); -/* D3D11: get pointer to IDXGISwapChain object */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_swap_chain(void); -/* D3D11: get pointer to ID3D11RenderTargetView object for rendering */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_render_view(void); -/* D3D11: get pointer ID3D11RenderTargetView object for msaa-resolve (may return null) */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_resolve_view(void); -/* D3D11: get pointer ID3D11DepthStencilView */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_depth_stencil_view(void); -/* Win32: get the HWND window handle */ -SOKOL_APP_API_DECL const void* sapp_win32_get_hwnd(void); - -/* WebGPU: get WGPUDevice handle */ -SOKOL_APP_API_DECL const void* sapp_wgpu_get_device(void); -/* WebGPU: get swapchain's WGPUTextureView handle for rendering */ -SOKOL_APP_API_DECL const void* sapp_wgpu_get_render_view(void); -/* WebGPU: get swapchain's MSAA-resolve WGPUTextureView (may return null) */ -SOKOL_APP_API_DECL const void* sapp_wgpu_get_resolve_view(void); -/* WebGPU: get swapchain's WGPUTextureView for the depth-stencil surface */ -SOKOL_APP_API_DECL const void* sapp_wgpu_get_depth_stencil_view(void); - -/* GL: get framebuffer object */ -SOKOL_APP_API_DECL uint32_t sapp_gl_get_framebuffer(void); -/* GL: get major version (only valid for desktop GL) */ -SOKOL_APP_API_DECL int sapp_gl_get_major_version(void); -/* GL: get minor version (only valid for desktop GL) */ -SOKOL_APP_API_DECL int sapp_gl_get_minor_version(void); - -/* Android: get native activity handle */ -SOKOL_APP_API_DECL const void* sapp_android_get_native_activity(void); - -#ifdef __cplusplus -} /* extern "C" */ - -/* reference-based equivalents for C++ */ -inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } - -#endif - -// this WinRT specific hack is required when wWinMain is in a static library -#if defined(_MSC_VER) && defined(UNICODE) -#include -#if defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#pragma comment(linker, "/include:wWinMain") -#endif -#endif - -#endif // SOKOL_APP_INCLUDED - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_APP_IMPL -#define SOKOL_APP_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sapp_desc.allocator to override memory allocation functions" -#endif - -#include // malloc, free -#include // memset, strncmp -#include // size_t -#include // roundf - -// helper macros -#define _sapp_def(val, def) (((val) == 0) ? (def) : (val)) -#define _sapp_absf(a) (((a)<0.0f)?-(a):(a)) - -#define _SAPP_MAX_TITLE_LENGTH (128) -#define _SAPP_FALLBACK_DEFAULT_WINDOW_WIDTH (640) -#define _SAPP_FALLBACK_DEFAULT_WINDOW_HEIGHT (480) -// NOTE: the pixel format values *must* be compatible with sg_pixel_format -#define _SAPP_PIXELFORMAT_RGBA8 (23) -#define _SAPP_PIXELFORMAT_BGRA8 (28) -#define _SAPP_PIXELFORMAT_DEPTH (43) -#define _SAPP_PIXELFORMAT_DEPTH_STENCIL (44) - -// check if the config defines are alright -#if defined(__APPLE__) - // see https://clang.llvm.org/docs/LanguageExtensions.html#automatic-reference-counting - #if !defined(__cplusplus) - #if __has_feature(objc_arc) && !__has_feature(objc_arc_fields) - #error "sokol_app.h requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)" - #endif - #endif - #define _SAPP_APPLE (1) - #include - #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE - /* MacOS */ - #define _SAPP_MACOS (1) - #if !defined(SOKOL_METAL) && !defined(SOKOL_GLCORE) - #error("sokol_app.h: unknown 3D API selected for MacOS, must be SOKOL_METAL or SOKOL_GLCORE") - #endif - #else - /* iOS or iOS Simulator */ - #define _SAPP_IOS (1) - #if !defined(SOKOL_METAL) && !defined(SOKOL_GLES3) - #error("sokol_app.h: unknown 3D API selected for iOS, must be SOKOL_METAL or SOKOL_GLES3") - #endif - #endif -#elif defined(__EMSCRIPTEN__) - /* emscripten (asm.js or wasm) */ - #define _SAPP_EMSCRIPTEN (1) - #if !defined(SOKOL_GLES3) && !defined(SOKOL_WGPU) - #error("sokol_app.h: unknown 3D API selected for emscripten, must be SOKOL_GLES3 or SOKOL_WGPU") - #endif -#elif defined(_WIN32) - /* Windows (D3D11 or GL) */ - #define _SAPP_WIN32 (1) - #if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE) && !defined(SOKOL_NOAPI) - #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11, SOKOL_GLCORE or SOKOL_NOAPI") - #endif -#elif defined(__ANDROID__) - /* Android */ - #define _SAPP_ANDROID (1) - #if !defined(SOKOL_GLES3) - #error("sokol_app.h: unknown 3D API selected for Android, must be SOKOL_GLES3") - #endif - #if defined(SOKOL_NO_ENTRY) - #error("sokol_app.h: SOKOL_NO_ENTRY is not supported on Android") - #endif -#elif defined(__linux__) || defined(__unix__) - /* Linux */ - #define _SAPP_LINUX (1) - #if defined(SOKOL_GLCORE) - #if !defined(SOKOL_FORCE_EGL) - #define _SAPP_GLX (1) - #endif - #define GL_GLEXT_PROTOTYPES - #include - #elif defined(SOKOL_GLES3) - #include - #include - #else - #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE, SOKOL_GLES3") - #endif -#else -#error "sokol_app.h: Unknown platform" -#endif - -#if defined(SOKOL_GLCORE) || defined(SOKOL_GLES3) - #define _SAPP_ANY_GL (1) -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif - -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif -#ifndef _SOKOL_UNUSED - #define _SOKOL_UNUSED(x) (void)(x) -#endif - -#if defined(_SAPP_APPLE) - #if defined(SOKOL_METAL) - #import - #import - #endif - #if defined(_SAPP_MACOS) - #if defined(_SAPP_ANY_GL) - #ifndef GL_SILENCE_DEPRECATION - #define GL_SILENCE_DEPRECATION - #endif - #include - #include - #endif - #elif defined(_SAPP_IOS) - #import - #if defined(_SAPP_ANY_GL) - #import - #include - #endif - #endif - #include - #include -#elif defined(_SAPP_EMSCRIPTEN) - #if defined(SOKOL_WGPU) - #include - #endif - #if defined(SOKOL_GLES3) - #include - #endif - #include - #include -#elif defined(_SAPP_WIN32) - #ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */ - #pragma warning(disable:4204) /* nonstandard extension used: non-constant aggregate initializer */ - #pragma warning(disable:4054) /* 'type cast': from function pointer */ - #pragma warning(disable:4055) /* 'type cast': from data pointer */ - #pragma warning(disable:4505) /* unreferenced local function has been removed */ - #pragma warning(disable:4115) /* /W4: 'ID3D11ModuleInstance': named type definition in parentheses (in d3d11.h) */ - #endif - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - #ifndef NOMINMAX - #define NOMINMAX - #endif - #include - #include - #include - #if !defined(SOKOL_NO_ENTRY) // if SOKOL_NO_ENTRY is defined, it's the applications' responsibility to use the right subsystem - #if defined(SOKOL_WIN32_FORCE_MAIN) - #pragma comment (linker, "/subsystem:console") - #else - #pragma comment (linker, "/subsystem:windows") - #endif - #endif - #include /* freopen_s() */ - #include /* wcslen() */ - - #pragma comment (lib, "kernel32") - #pragma comment (lib, "user32") - #pragma comment (lib, "shell32") /* CommandLineToArgvW, DragQueryFileW, DragFinished */ - #pragma comment (lib, "gdi32") - #if defined(SOKOL_D3D11) - #pragma comment (lib, "dxgi") - #pragma comment (lib, "d3d11") - #endif - - #if defined(SOKOL_D3D11) - #ifndef D3D11_NO_HELPERS - #define D3D11_NO_HELPERS - #endif - #include - #include - // DXGI_SWAP_EFFECT_FLIP_DISCARD is only defined in newer Windows SDKs, so don't depend on it - #define _SAPP_DXGI_SWAP_EFFECT_FLIP_DISCARD (4) - #endif - #ifndef WM_MOUSEHWHEEL /* see https://github.com/floooh/sokol/issues/138 */ - #define WM_MOUSEHWHEEL (0x020E) - #endif - #ifndef WM_DPICHANGED - #define WM_DPICHANGED (0x02E0) - #endif -#elif defined(_SAPP_ANDROID) - #include - #include - #include - #include - #include - #include - #include -#elif defined(_SAPP_LINUX) - #define GL_GLEXT_PROTOTYPES - #include - #include - #include - #include - #include - #include - #include - #include - #include /* XC_* font cursors */ - #include /* CARD32 */ - #if !defined(_SAPP_GLX) - #include - #endif - #include /* dlopen, dlsym, dlclose */ - #include /* LONG_MAX */ - #include /* only used a linker-guard, search for _sapp_linux_run() and see first comment */ - #include -#endif - -#if defined(_SAPP_APPLE) - // this is ARC compatible - #if defined(__cplusplus) - #define _SAPP_CLEAR_ARC_STRUCT(type, item) { item = type(); } - #else - #define _SAPP_CLEAR_ARC_STRUCT(type, item) { item = (type) { 0 }; } - #endif -#else - #define _SAPP_CLEAR_ARC_STRUCT(type, item) { _sapp_clear(&item, sizeof(item)); } -#endif - - -// ███████ ██████ █████ ███ ███ ███████ ████████ ██ ███ ███ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ████ ████ ██ ████ ██ ██ -// █████ ██████ ███████ ██ ████ ██ █████ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ████ ██████ -// -// >>frame timing -#define _SAPP_RING_NUM_SLOTS (256) -typedef struct { - int head; - int tail; - double buf[_SAPP_RING_NUM_SLOTS]; -} _sapp_ring_t; - -_SOKOL_PRIVATE int _sapp_ring_idx(int i) { - return i % _SAPP_RING_NUM_SLOTS; -} - -_SOKOL_PRIVATE void _sapp_ring_init(_sapp_ring_t* ring) { - ring->head = 0; - ring->tail = 0; -} - -_SOKOL_PRIVATE bool _sapp_ring_full(_sapp_ring_t* ring) { - return _sapp_ring_idx(ring->head + 1) == ring->tail; -} - -_SOKOL_PRIVATE bool _sapp_ring_empty(_sapp_ring_t* ring) { - return ring->head == ring->tail; -} - -_SOKOL_PRIVATE int _sapp_ring_count(_sapp_ring_t* ring) { - int count; - if (ring->head >= ring->tail) { - count = ring->head - ring->tail; - } - else { - count = (ring->head + _SAPP_RING_NUM_SLOTS) - ring->tail; - } - SOKOL_ASSERT((count >= 0) && (count < _SAPP_RING_NUM_SLOTS)); - return count; -} - -_SOKOL_PRIVATE void _sapp_ring_enqueue(_sapp_ring_t* ring, double val) { - SOKOL_ASSERT(!_sapp_ring_full(ring)); - ring->buf[ring->head] = val; - ring->head = _sapp_ring_idx(ring->head + 1); -} - -_SOKOL_PRIVATE double _sapp_ring_dequeue(_sapp_ring_t* ring) { - SOKOL_ASSERT(!_sapp_ring_empty(ring)); - double val = ring->buf[ring->tail]; - ring->tail = _sapp_ring_idx(ring->tail + 1); - return val; -} - -/* - NOTE: - - Q: Why not use CAMetalDrawable.presentedTime on macOS and iOS? - A: The value appears to be highly unstable during the first few - seconds, sometimes several frames are dropped in sequence, or - switch between 120 and 60 Hz for a few frames. Simply measuring - and averaging the frame time yielded a more stable frame duration. - Maybe switching to CVDisplayLink would yield better results. - Until then just measure the time. -*/ -typedef struct { - #if defined(_SAPP_APPLE) - struct { - mach_timebase_info_data_t timebase; - uint64_t start; - } mach; - #elif defined(_SAPP_EMSCRIPTEN) - // empty - #elif defined(_SAPP_WIN32) - struct { - LARGE_INTEGER freq; - LARGE_INTEGER start; - } win; - #else // Linux, Android, ... - #ifdef CLOCK_MONOTONIC - #define _SAPP_CLOCK_MONOTONIC CLOCK_MONOTONIC - #else - // on some embedded platforms, CLOCK_MONOTONIC isn't defined - #define _SAPP_CLOCK_MONOTONIC (1) - #endif - struct { - uint64_t start; - } posix; - #endif -} _sapp_timestamp_t; - -_SOKOL_PRIVATE int64_t _sapp_int64_muldiv(int64_t value, int64_t numer, int64_t denom) { - int64_t q = value / denom; - int64_t r = value % denom; - return q * numer + r * numer / denom; -} - -_SOKOL_PRIVATE void _sapp_timestamp_init(_sapp_timestamp_t* ts) { - #if defined(_SAPP_APPLE) - mach_timebase_info(&ts->mach.timebase); - ts->mach.start = mach_absolute_time(); - #elif defined(_SAPP_EMSCRIPTEN) - (void)ts; - #elif defined(_SAPP_WIN32) - QueryPerformanceFrequency(&ts->win.freq); - QueryPerformanceCounter(&ts->win.start); - #else - struct timespec tspec; - clock_gettime(_SAPP_CLOCK_MONOTONIC, &tspec); - ts->posix.start = (uint64_t)tspec.tv_sec*1000000000 + (uint64_t)tspec.tv_nsec; - #endif -} - -_SOKOL_PRIVATE double _sapp_timestamp_now(_sapp_timestamp_t* ts) { - #if defined(_SAPP_APPLE) - const uint64_t traw = mach_absolute_time() - ts->mach.start; - const uint64_t now = (uint64_t) _sapp_int64_muldiv((int64_t)traw, (int64_t)ts->mach.timebase.numer, (int64_t)ts->mach.timebase.denom); - return (double)now / 1000000000.0; - #elif defined(_SAPP_EMSCRIPTEN) - (void)ts; - SOKOL_ASSERT(false); - return 0.0; - #elif defined(_SAPP_WIN32) - LARGE_INTEGER qpc; - QueryPerformanceCounter(&qpc); - const uint64_t now = (uint64_t)_sapp_int64_muldiv(qpc.QuadPart - ts->win.start.QuadPart, 1000000000, ts->win.freq.QuadPart); - return (double)now / 1000000000.0; - #else - struct timespec tspec; - clock_gettime(_SAPP_CLOCK_MONOTONIC, &tspec); - const uint64_t now = ((uint64_t)tspec.tv_sec*1000000000 + (uint64_t)tspec.tv_nsec) - ts->posix.start; - return (double)now / 1000000000.0; - #endif -} - -typedef struct { - double last; - double accum; - double avg; - int spike_count; - int num; - _sapp_timestamp_t timestamp; - _sapp_ring_t ring; -} _sapp_timing_t; - -_SOKOL_PRIVATE void _sapp_timing_reset(_sapp_timing_t* t) { - t->last = 0.0; - t->accum = 0.0; - t->spike_count = 0; - t->num = 0; - _sapp_ring_init(&t->ring); -} - -_SOKOL_PRIVATE void _sapp_timing_init(_sapp_timing_t* t) { - t->avg = 1.0 / 60.0; // dummy value until first actual value is available - _sapp_timing_reset(t); - _sapp_timestamp_init(&t->timestamp); -} - -_SOKOL_PRIVATE void _sapp_timing_put(_sapp_timing_t* t, double dur) { - // arbitrary upper limit to ignore outliers (e.g. during window resizing, or debugging) - double min_dur = 0.0; - double max_dur = 0.1; - // if we have enough samples for a useful average, use a much tighter 'valid window' - if (_sapp_ring_full(&t->ring)) { - min_dur = t->avg * 0.8; - max_dur = t->avg * 1.2; - } - if ((dur < min_dur) || (dur > max_dur)) { - t->spike_count++; - // if there have been many spikes in a row, the display refresh rate - // might have changed, so a timing reset is needed - if (t->spike_count > 20) { - _sapp_timing_reset(t); - } - return; - } - if (_sapp_ring_full(&t->ring)) { - double old_val = _sapp_ring_dequeue(&t->ring); - t->accum -= old_val; - t->num -= 1; - } - _sapp_ring_enqueue(&t->ring, dur); - t->accum += dur; - t->num += 1; - SOKOL_ASSERT(t->num > 0); - t->avg = t->accum / t->num; - t->spike_count = 0; -} - -_SOKOL_PRIVATE void _sapp_timing_discontinuity(_sapp_timing_t* t) { - t->last = 0.0; -} - -_SOKOL_PRIVATE void _sapp_timing_measure(_sapp_timing_t* t) { - const double now = _sapp_timestamp_now(&t->timestamp); - if (t->last > 0.0) { - double dur = now - t->last; - _sapp_timing_put(t, dur); - } - t->last = now; -} - -_SOKOL_PRIVATE void _sapp_timing_external(_sapp_timing_t* t, double now) { - if (t->last > 0.0) { - double dur = now - t->last; - _sapp_timing_put(t, dur); - } - t->last = now; -} - -_SOKOL_PRIVATE double _sapp_timing_get_avg(_sapp_timing_t* t) { - return t->avg; -} - -// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██████ ██ ██ ██ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██████ ██████ ██ ███████ -// -// >> structs -#if defined(_SAPP_MACOS) -@interface _sapp_macos_app_delegate : NSObject -@end -@interface _sapp_macos_window : NSWindow -@end -@interface _sapp_macos_window_delegate : NSObject -@end -#if defined(SOKOL_METAL) - @interface _sapp_macos_view : MTKView - @end -#elif defined(SOKOL_GLCORE) - @interface _sapp_macos_view : NSOpenGLView - - (void)timerFired:(id)sender; - @end -#endif // SOKOL_GLCORE - -typedef struct { - uint32_t flags_changed_store; - uint8_t mouse_buttons; - NSWindow* window; - NSTrackingArea* tracking_area; - id keyup_monitor; - _sapp_macos_app_delegate* app_dlg; - _sapp_macos_window_delegate* win_dlg; - _sapp_macos_view* view; - NSCursor* cursors[_SAPP_MOUSECURSOR_NUM]; - #if defined(SOKOL_METAL) - id mtl_device; - #endif -} _sapp_macos_t; - -#endif // _SAPP_MACOS - -#if defined(_SAPP_IOS) - -@interface _sapp_app_delegate : NSObject -@end -@interface _sapp_textfield_dlg : NSObject -- (void)keyboardWasShown:(NSNotification*)notif; -- (void)keyboardWillBeHidden:(NSNotification*)notif; -- (void)keyboardDidChangeFrame:(NSNotification*)notif; -@end -#if defined(SOKOL_METAL) - @interface _sapp_ios_view : MTKView; - @end -#else - @interface _sapp_ios_view : GLKView - @end -#endif - -typedef struct { - UIWindow* window; - _sapp_ios_view* view; - UITextField* textfield; - _sapp_textfield_dlg* textfield_dlg; - #if defined(SOKOL_METAL) - UIViewController* view_ctrl; - id mtl_device; - #else - GLKViewController* view_ctrl; - EAGLContext* eagl_ctx; - #endif - bool suspended; -} _sapp_ios_t; - -#endif // _SAPP_IOS - -#if defined(_SAPP_EMSCRIPTEN) - -#if defined(SOKOL_WGPU) -typedef struct { - WGPUInstance instance; - WGPUAdapter adapter; - WGPUDevice device; - WGPUTextureFormat render_format; - WGPUSurface surface; - WGPUSwapChain swapchain; - WGPUTexture msaa_tex; - WGPUTextureView msaa_view; - WGPUTexture depth_stencil_tex; - WGPUTextureView depth_stencil_view; - WGPUTextureView swapchain_view; - bool async_init_done; -} _sapp_wgpu_t; -#endif - -typedef struct { - bool mouse_lock_requested; - uint16_t mouse_buttons; -} _sapp_emsc_t; -#endif // _SAPP_EMSCRIPTEN - -#if defined(SOKOL_D3D11) && defined(_SAPP_WIN32) -typedef struct { - ID3D11Device* device; - ID3D11DeviceContext* device_context; - ID3D11Texture2D* rt; - ID3D11RenderTargetView* rtv; - ID3D11Texture2D* msaa_rt; - ID3D11RenderTargetView* msaa_rtv; - ID3D11Texture2D* ds; - ID3D11DepthStencilView* dsv; - DXGI_SWAP_CHAIN_DESC swap_chain_desc; - IDXGISwapChain* swap_chain; - IDXGIDevice1* dxgi_device; - bool use_dxgi_frame_stats; - UINT sync_refresh_count; -} _sapp_d3d11_t; -#endif - -#if defined(_SAPP_WIN32) - -#ifndef DPI_ENUMS_DECLARED -typedef enum PROCESS_DPI_AWARENESS -{ - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, - PROCESS_PER_MONITOR_DPI_AWARE = 2 -} PROCESS_DPI_AWARENESS; -typedef enum MONITOR_DPI_TYPE { - MDT_EFFECTIVE_DPI = 0, - MDT_ANGULAR_DPI = 1, - MDT_RAW_DPI = 2, - MDT_DEFAULT = MDT_EFFECTIVE_DPI -} MONITOR_DPI_TYPE; -#endif // DPI_ENUMS_DECLARED - -typedef struct { - bool aware; - float content_scale; - float window_scale; - float mouse_scale; -} _sapp_win32_dpi_t; - -typedef struct { - HWND hwnd; - HMONITOR hmonitor; - HDC dc; - HICON big_icon; - HICON small_icon; - HCURSOR cursors[_SAPP_MOUSECURSOR_NUM]; - UINT orig_codepage; - LONG mouse_locked_x, mouse_locked_y; - RECT stored_window_rect; // used to restore window pos/size when toggling fullscreen => windowed - bool is_win10_or_greater; - bool in_create_window; - bool iconified; - bool mouse_tracked; - uint8_t mouse_capture_mask; - _sapp_win32_dpi_t dpi; - bool raw_input_mousepos_valid; - LONG raw_input_mousepos_x; - LONG raw_input_mousepos_y; - uint8_t raw_input_data[256]; -} _sapp_win32_t; - -#if defined(SOKOL_GLCORE) -#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_PIXEL_TYPE_ARB 0x2013 -#define WGL_TYPE_RGBA_ARB 0x202b -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_NO_ACCELERATION_ARB 0x2025 -#define WGL_RED_BITS_ARB 0x2015 -#define WGL_GREEN_BITS_ARB 0x2017 -#define WGL_BLUE_BITS_ARB 0x2019 -#define WGL_ALPHA_BITS_ARB 0x201b -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_SAMPLES_ARB 0x2042 -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define ERROR_INVALID_VERSION_ARB 0x2095 -#define ERROR_INVALID_PROFILE_ARB 0x2096 -#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 -typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); -typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); -typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC); -typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*); -typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC); -typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC); -typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR); -typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void); -typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC); - -typedef struct { - HINSTANCE opengl32; - HGLRC gl_ctx; - PFN_wglCreateContext CreateContext; - PFN_wglDeleteContext DeleteContext; - PFN_wglGetProcAddress GetProcAddress; - PFN_wglGetCurrentDC GetCurrentDC; - PFN_wglMakeCurrent MakeCurrent; - PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; - PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; - PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; - PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; - PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; - // special case glGetIntegerv - void (WINAPI *GetIntegerv)(uint32_t pname, int32_t* data); - bool ext_swap_control; - bool arb_multisample; - bool arb_pixel_format; - bool arb_create_context; - bool arb_create_context_profile; - HWND msg_hwnd; - HDC msg_dc; -} _sapp_wgl_t; -#endif // SOKOL_GLCORE - -#endif // _SAPP_WIN32 - -#if defined(_SAPP_ANDROID) -typedef enum { - _SOKOL_ANDROID_MSG_CREATE, - _SOKOL_ANDROID_MSG_RESUME, - _SOKOL_ANDROID_MSG_PAUSE, - _SOKOL_ANDROID_MSG_FOCUS, - _SOKOL_ANDROID_MSG_NO_FOCUS, - _SOKOL_ANDROID_MSG_SET_NATIVE_WINDOW, - _SOKOL_ANDROID_MSG_SET_INPUT_QUEUE, - _SOKOL_ANDROID_MSG_DESTROY, -} _sapp_android_msg_t; - -typedef struct { - pthread_t thread; - pthread_mutex_t mutex; - pthread_cond_t cond; - int read_from_main_fd; - int write_from_main_fd; -} _sapp_android_pt_t; - -typedef struct { - ANativeWindow* window; - AInputQueue* input; -} _sapp_android_resources_t; - -typedef struct { - ANativeActivity* activity; - _sapp_android_pt_t pt; - _sapp_android_resources_t pending; - _sapp_android_resources_t current; - ALooper* looper; - bool is_thread_started; - bool is_thread_stopping; - bool is_thread_stopped; - bool has_created; - bool has_resumed; - bool has_focus; - EGLConfig config; - EGLDisplay display; - EGLContext context; - EGLSurface surface; -} _sapp_android_t; - -#endif // _SAPP_ANDROID - -#if defined(_SAPP_LINUX) - -#define _SAPP_X11_XDND_VERSION (5) -#define _SAPP_X11_MAX_X11_KEYCODES (256) - -#define GLX_VENDOR 1 -#define GLX_RGBA_BIT 0x00000001 -#define GLX_WINDOW_BIT 0x00000001 -#define GLX_DRAWABLE_TYPE 0x8010 -#define GLX_RENDER_TYPE 0x8011 -#define GLX_DOUBLEBUFFER 5 -#define GLX_RED_SIZE 8 -#define GLX_GREEN_SIZE 9 -#define GLX_BLUE_SIZE 10 -#define GLX_ALPHA_SIZE 11 -#define GLX_DEPTH_SIZE 12 -#define GLX_STENCIL_SIZE 13 -#define GLX_SAMPLES 0x186a1 -#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define GLX_CONTEXT_FLAGS_ARB 0x2094 - -typedef XID GLXWindow; -typedef XID GLXDrawable; -typedef struct __GLXFBConfig* GLXFBConfig; -typedef struct __GLXcontext* GLXContext; -typedef void (*__GLXextproc)(void); - -typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*); -typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int); -typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*); -typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*); -typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext); -typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext); -typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable); -typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int); -typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*); -typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const char *procName); -typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); -typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig); -typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*); -typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); - -typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); -typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*); - -typedef struct { - bool available; - int major_opcode; - int event_base; - int error_base; - int major; - int minor; -} _sapp_xi_t; - -typedef struct { - int version; - Window source; - Atom format; - Atom XdndAware; - Atom XdndEnter; - Atom XdndPosition; - Atom XdndStatus; - Atom XdndActionCopy; - Atom XdndDrop; - Atom XdndFinished; - Atom XdndSelection; - Atom XdndTypeList; - Atom text_uri_list; -} _sapp_xdnd_t; - -typedef struct { - uint8_t mouse_buttons; - Display* display; - int screen; - Window root; - Colormap colormap; - Window window; - Cursor hidden_cursor; - Cursor cursors[_SAPP_MOUSECURSOR_NUM]; - int window_state; - float dpi; - unsigned char error_code; - Atom UTF8_STRING; - Atom WM_PROTOCOLS; - Atom WM_DELETE_WINDOW; - Atom WM_STATE; - Atom NET_WM_NAME; - Atom NET_WM_ICON_NAME; - Atom NET_WM_ICON; - Atom NET_WM_STATE; - Atom NET_WM_STATE_FULLSCREEN; - _sapp_xi_t xi; - _sapp_xdnd_t xdnd; - // XLib manual says keycodes are in the range [8, 255] inclusive. - // https://tronche.com/gui/x/xlib/input/keyboard-encoding.html - bool key_repeat[_SAPP_X11_MAX_X11_KEYCODES]; -} _sapp_x11_t; - -#if defined(_SAPP_GLX) - -typedef struct { - void* libgl; - int major; - int minor; - int event_base; - int error_base; - GLXContext ctx; - GLXWindow window; - - // GLX 1.3 functions - PFNGLXGETFBCONFIGSPROC GetFBConfigs; - PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib; - PFNGLXGETCLIENTSTRINGPROC GetClientString; - PFNGLXQUERYEXTENSIONPROC QueryExtension; - PFNGLXQUERYVERSIONPROC QueryVersion; - PFNGLXDESTROYCONTEXTPROC DestroyContext; - PFNGLXMAKECURRENTPROC MakeCurrent; - PFNGLXSWAPBUFFERSPROC SwapBuffers; - PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString; - PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig; - PFNGLXCREATEWINDOWPROC CreateWindow; - PFNGLXDESTROYWINDOWPROC DestroyWindow; - - // GLX 1.4 and extension functions - PFNGLXGETPROCADDRESSPROC GetProcAddress; - PFNGLXGETPROCADDRESSPROC GetProcAddressARB; - PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT; - PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; - PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; - - // special case glGetIntegerv - void (*GetIntegerv)(uint32_t pname, int32_t* data); - - // extension availability - bool EXT_swap_control; - bool MESA_swap_control; - bool ARB_multisample; - bool ARB_create_context; - bool ARB_create_context_profile; -} _sapp_glx_t; - -#else - -typedef struct { - EGLDisplay display; - EGLContext context; - EGLSurface surface; -} _sapp_egl_t; - -#endif // _SAPP_GLX -#endif // _SAPP_LINUX - -#if defined(_SAPP_ANY_GL) -typedef struct { - uint32_t framebuffer; -} _sapp_gl_t; -#endif - -typedef struct { - bool enabled; - int buf_size; - char* buffer; -} _sapp_clipboard_t; - -typedef struct { - bool enabled; - int max_files; - int max_path_length; - int num_files; - int buf_size; - char* buffer; -} _sapp_drop_t; - -typedef struct { - float x, y; - float dx, dy; - bool shown; - bool locked; - bool pos_valid; - sapp_mouse_cursor current_cursor; -} _sapp_mouse_t; - -typedef struct { - sapp_desc desc; - bool valid; - bool fullscreen; - bool first_frame; - bool init_called; - bool cleanup_called; - bool quit_requested; - bool quit_ordered; - bool event_consumed; - bool html5_ask_leave_site; - bool onscreen_keyboard_shown; - int window_width; - int window_height; - int framebuffer_width; - int framebuffer_height; - int sample_count; - int swap_interval; - float dpi_scale; - uint64_t frame_count; - _sapp_timing_t timing; - sapp_event event; - _sapp_mouse_t mouse; - _sapp_clipboard_t clipboard; - _sapp_drop_t drop; - sapp_icon_desc default_icon_desc; - uint32_t* default_icon_pixels; - #if defined(_SAPP_MACOS) - _sapp_macos_t macos; - #elif defined(_SAPP_IOS) - _sapp_ios_t ios; - #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_t emsc; - #if defined(SOKOL_WGPU) - _sapp_wgpu_t wgpu; - #endif - #elif defined(_SAPP_WIN32) - _sapp_win32_t win32; - #if defined(SOKOL_D3D11) - _sapp_d3d11_t d3d11; - #elif defined(SOKOL_GLCORE) - _sapp_wgl_t wgl; - #endif - #elif defined(_SAPP_ANDROID) - _sapp_android_t android; - #elif defined(_SAPP_LINUX) - _sapp_x11_t x11; - #if defined(_SAPP_GLX) - _sapp_glx_t glx; - #else - _sapp_egl_t egl; - #endif - #endif - #if defined(_SAPP_ANY_GL) - _sapp_gl_t gl; - #endif - char html5_canvas_selector[_SAPP_MAX_TITLE_LENGTH]; - char window_title[_SAPP_MAX_TITLE_LENGTH]; // UTF-8 - wchar_t window_title_wide[_SAPP_MAX_TITLE_LENGTH]; // UTF-32 or UCS-2 */ - sapp_keycode keycodes[SAPP_MAX_KEYCODES]; -} _sapp_t; -static _sapp_t _sapp; - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SAPP_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _sapp_log_messages[] = { - _SAPP_LOG_ITEMS -}; -#undef _SAPP_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SAPP_PANIC(code) _sapp_log(SAPP_LOGITEM_ ##code, 0, 0, __LINE__) -#define _SAPP_ERROR(code) _sapp_log(SAPP_LOGITEM_ ##code, 1, 0, __LINE__) -#define _SAPP_WARN(code) _sapp_log(SAPP_LOGITEM_ ##code, 2, 0, __LINE__) -#define _SAPP_INFO(code) _sapp_log(SAPP_LOGITEM_ ##code, 3, 0, __LINE__) - -static void _sapp_log(sapp_log_item log_item, uint32_t log_level, const char* msg, uint32_t line_nr) { - if (_sapp.desc.logger.func) { - const char* filename = 0; - #if defined(SOKOL_DEBUG) - filename = __FILE__; - if (0 == msg) { - msg = _sapp_log_messages[log_item]; - } - #endif - _sapp.desc.logger.func("sapp", log_level, log_item, msg, line_nr, filename, _sapp.desc.logger.user_data); - } - else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -_SOKOL_PRIVATE void _sapp_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -_SOKOL_PRIVATE void* _sapp_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_sapp.desc.allocator.alloc_fn) { - ptr = _sapp.desc.allocator.alloc_fn(size, _sapp.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SAPP_PANIC(MALLOC_FAILED); - } - return ptr; -} - -_SOKOL_PRIVATE void* _sapp_malloc_clear(size_t size) { - void* ptr = _sapp_malloc(size); - _sapp_clear(ptr, size); - return ptr; -} - -_SOKOL_PRIVATE void _sapp_free(void* ptr) { - if (_sapp.desc.allocator.free_fn) { - _sapp.desc.allocator.free_fn(ptr, _sapp.desc.allocator.user_data); - } - else { - free(ptr); - } -} - -// ██ ██ ███████ ██ ██████ ███████ ██████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ █████ ██ ██████ █████ ██████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ███████ ██ ███████ ██ ██ ███████ -// -// >>helpers -_SOKOL_PRIVATE void _sapp_call_init(void) { - if (_sapp.desc.init_cb) { - _sapp.desc.init_cb(); - } - else if (_sapp.desc.init_userdata_cb) { - _sapp.desc.init_userdata_cb(_sapp.desc.user_data); - } - _sapp.init_called = true; -} - -_SOKOL_PRIVATE void _sapp_call_frame(void) { - if (_sapp.init_called && !_sapp.cleanup_called) { - if (_sapp.desc.frame_cb) { - _sapp.desc.frame_cb(); - } - else if (_sapp.desc.frame_userdata_cb) { - _sapp.desc.frame_userdata_cb(_sapp.desc.user_data); - } - } -} - -_SOKOL_PRIVATE void _sapp_call_cleanup(void) { - if (!_sapp.cleanup_called) { - if (_sapp.desc.cleanup_cb) { - _sapp.desc.cleanup_cb(); - } - else if (_sapp.desc.cleanup_userdata_cb) { - _sapp.desc.cleanup_userdata_cb(_sapp.desc.user_data); - } - _sapp.cleanup_called = true; - } -} - -_SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) { - if (!_sapp.cleanup_called) { - if (_sapp.desc.event_cb) { - _sapp.desc.event_cb(e); - } - else if (_sapp.desc.event_userdata_cb) { - _sapp.desc.event_userdata_cb(e, _sapp.desc.user_data); - } - } - if (_sapp.event_consumed) { - _sapp.event_consumed = false; - return true; - } - else { - return false; - } -} - -_SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(int index) { - SOKOL_ASSERT(_sapp.drop.buffer); - SOKOL_ASSERT((index >= 0) && (index <= _sapp.drop.max_files)); - int offset = index * _sapp.drop.max_path_length; - SOKOL_ASSERT(offset < _sapp.drop.buf_size); - return &_sapp.drop.buffer[offset]; -} - -/* Copy a string into a fixed size buffer with guaranteed zero- - termination. - - Return false if the string didn't fit into the buffer and had to be clamped. - - FIXME: Currently UTF-8 strings might become invalid if the string - is clamped, because the last zero-byte might be written into - the middle of a multi-byte sequence. -*/ -_SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, int max_len) { - SOKOL_ASSERT(src && dst && (max_len > 0)); - char* const end = &(dst[max_len-1]); - char c = 0; - for (int i = 0; i < max_len; i++) { - c = *src; - if (c != 0) { - src++; - } - *dst++ = c; - } - /* truncated? */ - if (c != 0) { - *end = 0; - return false; - } - else { - return true; - } -} - -_SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sapp_desc res = *desc; - res.sample_count = _sapp_def(res.sample_count, 1); - res.swap_interval = _sapp_def(res.swap_interval, 1); - // NOTE: can't patch the default for gl_major_version and gl_minor_version - // independently, because a desired version 4.0 would be patched to 4.2 - // (or expressed differently: zero is a valid value for gl_minor_version - // and can't be used to indicate 'default') - if (0 == res.gl_major_version) { - #if defined(_SAPP_APPLE) - res.gl_major_version = 4; - res.gl_minor_version = 1; - #else - res.gl_major_version = 4; - res.gl_minor_version = 3; - #endif - } - res.html5_canvas_name = _sapp_def(res.html5_canvas_name, "canvas"); - res.clipboard_size = _sapp_def(res.clipboard_size, 8192); - res.max_dropped_files = _sapp_def(res.max_dropped_files, 1); - res.max_dropped_file_path_length = _sapp_def(res.max_dropped_file_path_length, 2048); - res.window_title = _sapp_def(res.window_title, "sokol_app"); - return res; -} - -_SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { - SOKOL_ASSERT(desc); - SOKOL_ASSERT(desc->width >= 0); - SOKOL_ASSERT(desc->height >= 0); - SOKOL_ASSERT(desc->sample_count >= 0); - SOKOL_ASSERT(desc->swap_interval >= 0); - SOKOL_ASSERT(desc->clipboard_size >= 0); - SOKOL_ASSERT(desc->max_dropped_files >= 0); - SOKOL_ASSERT(desc->max_dropped_file_path_length >= 0); - _SAPP_CLEAR_ARC_STRUCT(_sapp_t, _sapp); - _sapp.desc = _sapp_desc_defaults(desc); - _sapp.first_frame = true; - // NOTE: _sapp.desc.width/height may be 0! Platform backends need to deal with this - _sapp.window_width = _sapp.desc.width; - _sapp.window_height = _sapp.desc.height; - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; - _sapp.sample_count = _sapp.desc.sample_count; - _sapp.swap_interval = _sapp.desc.swap_interval; - _sapp.html5_canvas_selector[0] = '#'; - _sapp_strcpy(_sapp.desc.html5_canvas_name, &_sapp.html5_canvas_selector[1], sizeof(_sapp.html5_canvas_selector) - 1); - _sapp.desc.html5_canvas_name = &_sapp.html5_canvas_selector[1]; - _sapp.html5_ask_leave_site = _sapp.desc.html5_ask_leave_site; - _sapp.clipboard.enabled = _sapp.desc.enable_clipboard; - if (_sapp.clipboard.enabled) { - _sapp.clipboard.buf_size = _sapp.desc.clipboard_size; - _sapp.clipboard.buffer = (char*) _sapp_malloc_clear((size_t)_sapp.clipboard.buf_size); - } - _sapp.drop.enabled = _sapp.desc.enable_dragndrop; - if (_sapp.drop.enabled) { - _sapp.drop.max_files = _sapp.desc.max_dropped_files; - _sapp.drop.max_path_length = _sapp.desc.max_dropped_file_path_length; - _sapp.drop.buf_size = _sapp.drop.max_files * _sapp.drop.max_path_length; - _sapp.drop.buffer = (char*) _sapp_malloc_clear((size_t)_sapp.drop.buf_size); - } - _sapp_strcpy(_sapp.desc.window_title, _sapp.window_title, sizeof(_sapp.window_title)); - _sapp.desc.window_title = _sapp.window_title; - _sapp.dpi_scale = 1.0f; - _sapp.fullscreen = _sapp.desc.fullscreen; - _sapp.mouse.shown = true; - _sapp_timing_init(&_sapp.timing); -} - -_SOKOL_PRIVATE void _sapp_discard_state(void) { - if (_sapp.clipboard.enabled) { - SOKOL_ASSERT(_sapp.clipboard.buffer); - _sapp_free((void*)_sapp.clipboard.buffer); - } - if (_sapp.drop.enabled) { - SOKOL_ASSERT(_sapp.drop.buffer); - _sapp_free((void*)_sapp.drop.buffer); - } - if (_sapp.default_icon_pixels) { - _sapp_free((void*)_sapp.default_icon_pixels); - } - _SAPP_CLEAR_ARC_STRUCT(_sapp_t, _sapp); -} - -_SOKOL_PRIVATE void _sapp_init_event(sapp_event_type type) { - _sapp_clear(&_sapp.event, sizeof(_sapp.event)); - _sapp.event.type = type; - _sapp.event.frame_count = _sapp.frame_count; - _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID; - _sapp.event.window_width = _sapp.window_width; - _sapp.event.window_height = _sapp.window_height; - _sapp.event.framebuffer_width = _sapp.framebuffer_width; - _sapp.event.framebuffer_height = _sapp.framebuffer_height; - _sapp.event.mouse_x = _sapp.mouse.x; - _sapp.event.mouse_y = _sapp.mouse.y; - _sapp.event.mouse_dx = _sapp.mouse.dx; - _sapp.event.mouse_dy = _sapp.mouse.dy; -} - -_SOKOL_PRIVATE bool _sapp_events_enabled(void) { - /* only send events when an event callback is set, and the init function was called */ - return (_sapp.desc.event_cb || _sapp.desc.event_userdata_cb) && _sapp.init_called; -} - -_SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) { - if ((scan_code >= 0) && (scan_code < SAPP_MAX_KEYCODES)) { - return _sapp.keycodes[scan_code]; - } - else { - return SAPP_KEYCODE_INVALID; - } -} - -_SOKOL_PRIVATE void _sapp_clear_drop_buffer(void) { - if (_sapp.drop.enabled) { - SOKOL_ASSERT(_sapp.drop.buffer); - _sapp_clear(_sapp.drop.buffer, (size_t)_sapp.drop.buf_size); - } -} - -_SOKOL_PRIVATE void _sapp_frame(void) { - if (_sapp.first_frame) { - _sapp.first_frame = false; - _sapp_call_init(); - } - _sapp_call_frame(); - _sapp.frame_count++; -} - -_SOKOL_PRIVATE bool _sapp_image_validate(const sapp_image_desc* desc) { - SOKOL_ASSERT(desc->width > 0); - SOKOL_ASSERT(desc->height > 0); - SOKOL_ASSERT(desc->pixels.ptr != 0); - SOKOL_ASSERT(desc->pixels.size > 0); - const size_t wh_size = (size_t)(desc->width * desc->height) * sizeof(uint32_t); - if (wh_size != desc->pixels.size) { - _SAPP_ERROR(IMAGE_DATA_SIZE_MISMATCH); - return false; - } - return true; -} - -_SOKOL_PRIVATE int _sapp_image_bestmatch(const sapp_image_desc image_descs[], int num_images, int width, int height) { - int least_diff = 0x7FFFFFFF; - int least_index = 0; - for (int i = 0; i < num_images; i++) { - int diff = (image_descs[i].width * image_descs[i].height) - (width * height); - if (diff < 0) { - diff = -diff; - } - if (diff < least_diff) { - least_diff = diff; - least_index = i; - } - } - return least_index; -} - -_SOKOL_PRIVATE int _sapp_icon_num_images(const sapp_icon_desc* desc) { - int index = 0; - for (; index < SAPP_MAX_ICONIMAGES; index++) { - if (0 == desc->images[index].pixels.ptr) { - break; - } - } - return index; -} - -_SOKOL_PRIVATE bool _sapp_validate_icon_desc(const sapp_icon_desc* desc, int num_images) { - SOKOL_ASSERT(num_images <= SAPP_MAX_ICONIMAGES); - for (int i = 0; i < num_images; i++) { - const sapp_image_desc* img_desc = &desc->images[i]; - if (!_sapp_image_validate(img_desc)) { - return false; - } - } - return true; -} - -_SOKOL_PRIVATE void _sapp_setup_default_icon(void) { - SOKOL_ASSERT(0 == _sapp.default_icon_pixels); - - const int num_icons = 3; - const int icon_sizes[3] = { 16, 32, 64 }; // must be multiple of 8! - - // allocate a pixel buffer for all icon pixels - int all_num_pixels = 0; - for (int i = 0; i < num_icons; i++) { - all_num_pixels += icon_sizes[i] * icon_sizes[i]; - } - _sapp.default_icon_pixels = (uint32_t*) _sapp_malloc_clear((size_t)all_num_pixels * sizeof(uint32_t)); - - // initialize default_icon_desc struct - uint32_t* dst = _sapp.default_icon_pixels; - const uint32_t* dst_end = dst + all_num_pixels; - (void)dst_end; // silence unused warning in release mode - for (int i = 0; i < num_icons; i++) { - const int dim = (int) icon_sizes[i]; - const int num_pixels = dim * dim; - sapp_image_desc* img_desc = &_sapp.default_icon_desc.images[i]; - img_desc->width = dim; - img_desc->height = dim; - img_desc->pixels.ptr = dst; - img_desc->pixels.size = (size_t)num_pixels * sizeof(uint32_t); - dst += num_pixels; - } - SOKOL_ASSERT(dst == dst_end); - - // Amstrad CPC font 'S' - const uint8_t tile[8] = { - 0x3C, - 0x66, - 0x60, - 0x3C, - 0x06, - 0x66, - 0x3C, - 0x00, - }; - // rainbow colors - const uint32_t colors[8] = { - 0xFF4370FF, - 0xFF26A7FF, - 0xFF58EEFF, - 0xFF57E1D4, - 0xFF65CC9C, - 0xFF6ABB66, - 0xFFF5A542, - 0xFFC2577E, - }; - dst = _sapp.default_icon_pixels; - const uint32_t blank = 0x00FFFFFF; - const uint32_t shadow = 0xFF000000; - for (int i = 0; i < num_icons; i++) { - const int dim = icon_sizes[i]; - SOKOL_ASSERT((dim % 8) == 0); - const int scale = dim / 8; - for (int ty = 0, y = 0; ty < 8; ty++) { - const uint32_t color = colors[ty]; - for (int sy = 0; sy < scale; sy++, y++) { - uint8_t bits = tile[ty]; - for (int tx = 0, x = 0; tx < 8; tx++, bits<<=1) { - uint32_t pixel = (0 == (bits & 0x80)) ? blank : color; - for (int sx = 0; sx < scale; sx++, x++) { - SOKOL_ASSERT(dst < dst_end); - *dst++ = pixel; - } - } - } - } - } - SOKOL_ASSERT(dst == dst_end); - - // right shadow - dst = _sapp.default_icon_pixels; - for (int i = 0; i < num_icons; i++) { - const int dim = icon_sizes[i]; - for (int y = 0; y < dim; y++) { - uint32_t prev_color = blank; - for (int x = 0; x < dim; x++) { - const int dst_index = y * dim + x; - const uint32_t cur_color = dst[dst_index]; - if ((cur_color == blank) && (prev_color != blank)) { - dst[dst_index] = shadow; - } - prev_color = cur_color; - } - } - dst += dim * dim; - } - SOKOL_ASSERT(dst == dst_end); - - // bottom shadow - dst = _sapp.default_icon_pixels; - for (int i = 0; i < num_icons; i++) { - const int dim = icon_sizes[i]; - for (int x = 0; x < dim; x++) { - uint32_t prev_color = blank; - for (int y = 0; y < dim; y++) { - const int dst_index = y * dim + x; - const uint32_t cur_color = dst[dst_index]; - if ((cur_color == blank) && (prev_color != blank)) { - dst[dst_index] = shadow; - } - prev_color = cur_color; - } - } - dst += dim * dim; - } - SOKOL_ASSERT(dst == dst_end); -} - -// █████ ██████ ██████ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██ █████ -// ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ -// -// >>apple -#if defined(_SAPP_APPLE) - -#if __has_feature(objc_arc) -#define _SAPP_OBJC_RELEASE(obj) { obj = nil; } -#else -#define _SAPP_OBJC_RELEASE(obj) { [obj release]; obj = nil; } -#endif - -// ███ ███ █████ ██████ ██████ ███████ -// ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ ███████ ██ ██ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██████ ██████ ███████ -// -// >>macos -#if defined(_SAPP_MACOS) - -_SOKOL_PRIVATE void _sapp_macos_init_keytable(void) { - _sapp.keycodes[0x1D] = SAPP_KEYCODE_0; - _sapp.keycodes[0x12] = SAPP_KEYCODE_1; - _sapp.keycodes[0x13] = SAPP_KEYCODE_2; - _sapp.keycodes[0x14] = SAPP_KEYCODE_3; - _sapp.keycodes[0x15] = SAPP_KEYCODE_4; - _sapp.keycodes[0x17] = SAPP_KEYCODE_5; - _sapp.keycodes[0x16] = SAPP_KEYCODE_6; - _sapp.keycodes[0x1A] = SAPP_KEYCODE_7; - _sapp.keycodes[0x1C] = SAPP_KEYCODE_8; - _sapp.keycodes[0x19] = SAPP_KEYCODE_9; - _sapp.keycodes[0x00] = SAPP_KEYCODE_A; - _sapp.keycodes[0x0B] = SAPP_KEYCODE_B; - _sapp.keycodes[0x08] = SAPP_KEYCODE_C; - _sapp.keycodes[0x02] = SAPP_KEYCODE_D; - _sapp.keycodes[0x0E] = SAPP_KEYCODE_E; - _sapp.keycodes[0x03] = SAPP_KEYCODE_F; - _sapp.keycodes[0x05] = SAPP_KEYCODE_G; - _sapp.keycodes[0x04] = SAPP_KEYCODE_H; - _sapp.keycodes[0x22] = SAPP_KEYCODE_I; - _sapp.keycodes[0x26] = SAPP_KEYCODE_J; - _sapp.keycodes[0x28] = SAPP_KEYCODE_K; - _sapp.keycodes[0x25] = SAPP_KEYCODE_L; - _sapp.keycodes[0x2E] = SAPP_KEYCODE_M; - _sapp.keycodes[0x2D] = SAPP_KEYCODE_N; - _sapp.keycodes[0x1F] = SAPP_KEYCODE_O; - _sapp.keycodes[0x23] = SAPP_KEYCODE_P; - _sapp.keycodes[0x0C] = SAPP_KEYCODE_Q; - _sapp.keycodes[0x0F] = SAPP_KEYCODE_R; - _sapp.keycodes[0x01] = SAPP_KEYCODE_S; - _sapp.keycodes[0x11] = SAPP_KEYCODE_T; - _sapp.keycodes[0x20] = SAPP_KEYCODE_U; - _sapp.keycodes[0x09] = SAPP_KEYCODE_V; - _sapp.keycodes[0x0D] = SAPP_KEYCODE_W; - _sapp.keycodes[0x07] = SAPP_KEYCODE_X; - _sapp.keycodes[0x10] = SAPP_KEYCODE_Y; - _sapp.keycodes[0x06] = SAPP_KEYCODE_Z; - _sapp.keycodes[0x27] = SAPP_KEYCODE_APOSTROPHE; - _sapp.keycodes[0x2A] = SAPP_KEYCODE_BACKSLASH; - _sapp.keycodes[0x2B] = SAPP_KEYCODE_COMMA; - _sapp.keycodes[0x18] = SAPP_KEYCODE_EQUAL; - _sapp.keycodes[0x32] = SAPP_KEYCODE_GRAVE_ACCENT; - _sapp.keycodes[0x21] = SAPP_KEYCODE_LEFT_BRACKET; - _sapp.keycodes[0x1B] = SAPP_KEYCODE_MINUS; - _sapp.keycodes[0x2F] = SAPP_KEYCODE_PERIOD; - _sapp.keycodes[0x1E] = SAPP_KEYCODE_RIGHT_BRACKET; - _sapp.keycodes[0x29] = SAPP_KEYCODE_SEMICOLON; - _sapp.keycodes[0x2C] = SAPP_KEYCODE_SLASH; - _sapp.keycodes[0x0A] = SAPP_KEYCODE_WORLD_1; - _sapp.keycodes[0x33] = SAPP_KEYCODE_BACKSPACE; - _sapp.keycodes[0x39] = SAPP_KEYCODE_CAPS_LOCK; - _sapp.keycodes[0x75] = SAPP_KEYCODE_DELETE; - _sapp.keycodes[0x7D] = SAPP_KEYCODE_DOWN; - _sapp.keycodes[0x77] = SAPP_KEYCODE_END; - _sapp.keycodes[0x24] = SAPP_KEYCODE_ENTER; - _sapp.keycodes[0x35] = SAPP_KEYCODE_ESCAPE; - _sapp.keycodes[0x7A] = SAPP_KEYCODE_F1; - _sapp.keycodes[0x78] = SAPP_KEYCODE_F2; - _sapp.keycodes[0x63] = SAPP_KEYCODE_F3; - _sapp.keycodes[0x76] = SAPP_KEYCODE_F4; - _sapp.keycodes[0x60] = SAPP_KEYCODE_F5; - _sapp.keycodes[0x61] = SAPP_KEYCODE_F6; - _sapp.keycodes[0x62] = SAPP_KEYCODE_F7; - _sapp.keycodes[0x64] = SAPP_KEYCODE_F8; - _sapp.keycodes[0x65] = SAPP_KEYCODE_F9; - _sapp.keycodes[0x6D] = SAPP_KEYCODE_F10; - _sapp.keycodes[0x67] = SAPP_KEYCODE_F11; - _sapp.keycodes[0x6F] = SAPP_KEYCODE_F12; - _sapp.keycodes[0x69] = SAPP_KEYCODE_F13; - _sapp.keycodes[0x6B] = SAPP_KEYCODE_F14; - _sapp.keycodes[0x71] = SAPP_KEYCODE_F15; - _sapp.keycodes[0x6A] = SAPP_KEYCODE_F16; - _sapp.keycodes[0x40] = SAPP_KEYCODE_F17; - _sapp.keycodes[0x4F] = SAPP_KEYCODE_F18; - _sapp.keycodes[0x50] = SAPP_KEYCODE_F19; - _sapp.keycodes[0x5A] = SAPP_KEYCODE_F20; - _sapp.keycodes[0x73] = SAPP_KEYCODE_HOME; - _sapp.keycodes[0x72] = SAPP_KEYCODE_INSERT; - _sapp.keycodes[0x7B] = SAPP_KEYCODE_LEFT; - _sapp.keycodes[0x3A] = SAPP_KEYCODE_LEFT_ALT; - _sapp.keycodes[0x3B] = SAPP_KEYCODE_LEFT_CONTROL; - _sapp.keycodes[0x38] = SAPP_KEYCODE_LEFT_SHIFT; - _sapp.keycodes[0x37] = SAPP_KEYCODE_LEFT_SUPER; - _sapp.keycodes[0x6E] = SAPP_KEYCODE_MENU; - _sapp.keycodes[0x47] = SAPP_KEYCODE_NUM_LOCK; - _sapp.keycodes[0x79] = SAPP_KEYCODE_PAGE_DOWN; - _sapp.keycodes[0x74] = SAPP_KEYCODE_PAGE_UP; - _sapp.keycodes[0x7C] = SAPP_KEYCODE_RIGHT; - _sapp.keycodes[0x3D] = SAPP_KEYCODE_RIGHT_ALT; - _sapp.keycodes[0x3E] = SAPP_KEYCODE_RIGHT_CONTROL; - _sapp.keycodes[0x3C] = SAPP_KEYCODE_RIGHT_SHIFT; - _sapp.keycodes[0x36] = SAPP_KEYCODE_RIGHT_SUPER; - _sapp.keycodes[0x31] = SAPP_KEYCODE_SPACE; - _sapp.keycodes[0x30] = SAPP_KEYCODE_TAB; - _sapp.keycodes[0x7E] = SAPP_KEYCODE_UP; - _sapp.keycodes[0x52] = SAPP_KEYCODE_KP_0; - _sapp.keycodes[0x53] = SAPP_KEYCODE_KP_1; - _sapp.keycodes[0x54] = SAPP_KEYCODE_KP_2; - _sapp.keycodes[0x55] = SAPP_KEYCODE_KP_3; - _sapp.keycodes[0x56] = SAPP_KEYCODE_KP_4; - _sapp.keycodes[0x57] = SAPP_KEYCODE_KP_5; - _sapp.keycodes[0x58] = SAPP_KEYCODE_KP_6; - _sapp.keycodes[0x59] = SAPP_KEYCODE_KP_7; - _sapp.keycodes[0x5B] = SAPP_KEYCODE_KP_8; - _sapp.keycodes[0x5C] = SAPP_KEYCODE_KP_9; - _sapp.keycodes[0x45] = SAPP_KEYCODE_KP_ADD; - _sapp.keycodes[0x41] = SAPP_KEYCODE_KP_DECIMAL; - _sapp.keycodes[0x4B] = SAPP_KEYCODE_KP_DIVIDE; - _sapp.keycodes[0x4C] = SAPP_KEYCODE_KP_ENTER; - _sapp.keycodes[0x51] = SAPP_KEYCODE_KP_EQUAL; - _sapp.keycodes[0x43] = SAPP_KEYCODE_KP_MULTIPLY; - _sapp.keycodes[0x4E] = SAPP_KEYCODE_KP_SUBTRACT; -} - -_SOKOL_PRIVATE void _sapp_macos_discard_state(void) { - // NOTE: it's safe to call [release] on a nil object - if (_sapp.macos.keyup_monitor != nil) { - [NSEvent removeMonitor:_sapp.macos.keyup_monitor]; - // NOTE: removeMonitor also releases the object - _sapp.macos.keyup_monitor = nil; - } - _SAPP_OBJC_RELEASE(_sapp.macos.tracking_area); - _SAPP_OBJC_RELEASE(_sapp.macos.app_dlg); - _SAPP_OBJC_RELEASE(_sapp.macos.win_dlg); - _SAPP_OBJC_RELEASE(_sapp.macos.view); - #if defined(SOKOL_METAL) - _SAPP_OBJC_RELEASE(_sapp.macos.mtl_device); - #endif - _SAPP_OBJC_RELEASE(_sapp.macos.window); -} - -// undocumented methods for creating cursors (see GLFW 3.4 and imgui_impl_osx.mm) -@interface NSCursor() -+ (id)_windowResizeNorthWestSouthEastCursor; -+ (id)_windowResizeNorthEastSouthWestCursor; -+ (id)_windowResizeNorthSouthCursor; -+ (id)_windowResizeEastWestCursor; -@end - -_SOKOL_PRIVATE void _sapp_macos_init_cursors(void) { - _sapp.macos.cursors[SAPP_MOUSECURSOR_DEFAULT] = nil; // not a bug - _sapp.macos.cursors[SAPP_MOUSECURSOR_ARROW] = [NSCursor arrowCursor]; - _sapp.macos.cursors[SAPP_MOUSECURSOR_IBEAM] = [NSCursor IBeamCursor]; - _sapp.macos.cursors[SAPP_MOUSECURSOR_CROSSHAIR] = [NSCursor crosshairCursor]; - _sapp.macos.cursors[SAPP_MOUSECURSOR_POINTING_HAND] = [NSCursor pointingHandCursor]; - _sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_EW] = [NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)] ? [NSCursor _windowResizeEastWestCursor] : [NSCursor resizeLeftRightCursor]; - _sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_NS] = [NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)] ? [NSCursor _windowResizeNorthSouthCursor] : [NSCursor resizeUpDownCursor]; - _sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_NWSE] = [NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)] ? [NSCursor _windowResizeNorthWestSouthEastCursor] : [NSCursor closedHandCursor]; - _sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_NESW] = [NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)] ? [NSCursor _windowResizeNorthEastSouthWestCursor] : [NSCursor closedHandCursor]; - _sapp.macos.cursors[SAPP_MOUSECURSOR_RESIZE_ALL] = [NSCursor closedHandCursor]; - _sapp.macos.cursors[SAPP_MOUSECURSOR_NOT_ALLOWED] = [NSCursor operationNotAllowedCursor]; -} - -_SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { - _sapp_init_state(desc); - _sapp_macos_init_keytable(); - [NSApplication sharedApplication]; - - // set the application dock icon as early as possible, otherwise - // the dummy icon will be visible for a short time - sapp_set_icon(&_sapp.desc.icon); - _sapp.macos.app_dlg = [[_sapp_macos_app_delegate alloc] init]; - NSApp.delegate = _sapp.macos.app_dlg; - - // workaround for "no key-up sent while Cmd is pressed" taken from GLFW: - NSEvent* (^keyup_monitor)(NSEvent*) = ^NSEvent* (NSEvent* event) { - if ([event modifierFlags] & NSEventModifierFlagCommand) { - [[NSApp keyWindow] sendEvent:event]; - } - return event; - }; - _sapp.macos.keyup_monitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp handler:keyup_monitor]; - - [NSApp run]; - // NOTE: [NSApp run] never returns, instead cleanup code - // must be put into applicationWillTerminate -} - -/* MacOS entry function */ -#if !defined(SOKOL_NO_ENTRY) -int main(int argc, char* argv[]) { - sapp_desc desc = sokol_main(argc, argv); - _sapp_macos_run(&desc); - return 0; -} -#endif /* SOKOL_NO_ENTRY */ - -_SOKOL_PRIVATE uint32_t _sapp_macos_mods(NSEvent* ev) { - const NSEventModifierFlags f = (ev == nil) ? NSEvent.modifierFlags : ev.modifierFlags; - const NSUInteger b = NSEvent.pressedMouseButtons; - uint32_t m = 0; - if (f & NSEventModifierFlagShift) { - m |= SAPP_MODIFIER_SHIFT; - } - if (f & NSEventModifierFlagControl) { - m |= SAPP_MODIFIER_CTRL; - } - if (f & NSEventModifierFlagOption) { - m |= SAPP_MODIFIER_ALT; - } - if (f & NSEventModifierFlagCommand) { - m |= SAPP_MODIFIER_SUPER; - } - if (0 != (b & (1<<0))) { - m |= SAPP_MODIFIER_LMB; - } - if (0 != (b & (1<<1))) { - m |= SAPP_MODIFIER_RMB; - } - if (0 != (b & (1<<2))) { - m |= SAPP_MODIFIER_MMB; - } - return m; -} - -_SOKOL_PRIVATE void _sapp_macos_mouse_event(sapp_event_type type, sapp_mousebutton btn, uint32_t mod) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp.event.mouse_button = btn; - _sapp.event.modifiers = mod; - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_macos_key_event(sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mod) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp.event.key_code = key; - _sapp.event.key_repeat = repeat; - _sapp.event.modifiers = mod; - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_macos_app_event(sapp_event_type type) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp_call_event(&_sapp.event); - } -} - -/* NOTE: unlike the iOS version of this function, the macOS version - can dynamically update the DPI scaling factor when a window is moved - between HighDPI / LowDPI screens. -*/ -_SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { - if (_sapp.desc.high_dpi) { - _sapp.dpi_scale = [_sapp.macos.window screen].backingScaleFactor; - } - else { - _sapp.dpi_scale = 1.0f; - } - _sapp.macos.view.layer.contentsScale = _sapp.dpi_scale; // NOTE: needed because we set layerContentsPlacement to a non-scaling value in windowWillStartLiveResize. - const NSRect bounds = [_sapp.macos.view bounds]; - _sapp.window_width = (int)roundf(bounds.size.width); - _sapp.window_height = (int)roundf(bounds.size.height); - #if defined(SOKOL_METAL) - _sapp.framebuffer_width = (int)roundf(bounds.size.width * _sapp.dpi_scale); - _sapp.framebuffer_height = (int)roundf(bounds.size.height * _sapp.dpi_scale); - const CGSize fb_size = _sapp.macos.view.drawableSize; - const int cur_fb_width = (int)roundf(fb_size.width); - const int cur_fb_height = (int)roundf(fb_size.height); - const bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || - (_sapp.framebuffer_height != cur_fb_height); - #elif defined(SOKOL_GLCORE) - const int cur_fb_width = (int)roundf(bounds.size.width * _sapp.dpi_scale); - const int cur_fb_height = (int)roundf(bounds.size.height * _sapp.dpi_scale); - const bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || - (_sapp.framebuffer_height != cur_fb_height); - _sapp.framebuffer_width = cur_fb_width; - _sapp.framebuffer_height = cur_fb_height; - #endif - if (_sapp.framebuffer_width == 0) { - _sapp.framebuffer_width = 1; - } - if (_sapp.framebuffer_height == 0) { - _sapp.framebuffer_height = 1; - } - if (_sapp.window_width == 0) { - _sapp.window_width = 1; - } - if (_sapp.window_height == 0) { - _sapp.window_height = 1; - } - if (dim_changed) { - #if defined(SOKOL_METAL) - CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height }; - _sapp.macos.view.drawableSize = drawable_size; - #else - // nothing to do for GL? - #endif - if (!_sapp.first_frame) { - _sapp_macos_app_event(SAPP_EVENTTYPE_RESIZED); - } - } -} - -_SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(void) { - /* NOTE: the _sapp.fullscreen flag is also notified by the - windowDidEnterFullscreen / windowDidExitFullscreen - event handlers - */ - _sapp.fullscreen = !_sapp.fullscreen; - [_sapp.macos.window toggleFullScreen:nil]; -} - -_SOKOL_PRIVATE void _sapp_macos_set_clipboard_string(const char* str) { - @autoreleasepool { - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - [pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil]; - [pasteboard setString:@(str) forType:NSPasteboardTypeString]; - } -} - -_SOKOL_PRIVATE const char* _sapp_macos_get_clipboard_string(void) { - SOKOL_ASSERT(_sapp.clipboard.buffer); - @autoreleasepool { - _sapp.clipboard.buffer[0] = 0; - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - if (![[pasteboard types] containsObject:NSPasteboardTypeString]) { - return _sapp.clipboard.buffer; - } - NSString* str = [pasteboard stringForType:NSPasteboardTypeString]; - if (!str) { - return _sapp.clipboard.buffer; - } - _sapp_strcpy([str UTF8String], _sapp.clipboard.buffer, _sapp.clipboard.buf_size); - } - return _sapp.clipboard.buffer; -} - -_SOKOL_PRIVATE void _sapp_macos_update_window_title(void) { - [_sapp.macos.window setTitle: [NSString stringWithUTF8String:_sapp.window_title]]; -} - -_SOKOL_PRIVATE void _sapp_macos_mouse_update_from_nspoint(NSPoint mouse_pos, bool clear_dxdy) { - if (!_sapp.mouse.locked) { - float new_x = mouse_pos.x * _sapp.dpi_scale; - float new_y = _sapp.framebuffer_height - (mouse_pos.y * _sapp.dpi_scale) - 1; - if (clear_dxdy) { - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - } - else if (_sapp.mouse.pos_valid) { - // don't update dx/dy in the very first update - _sapp.mouse.dx = new_x - _sapp.mouse.x; - _sapp.mouse.dy = new_y - _sapp.mouse.y; - } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; - } -} - -_SOKOL_PRIVATE void _sapp_macos_mouse_update_from_nsevent(NSEvent* event, bool clear_dxdy) { - _sapp_macos_mouse_update_from_nspoint(event.locationInWindow, clear_dxdy); -} - -_SOKOL_PRIVATE void _sapp_macos_show_mouse(bool visible) { - /* NOTE: this function is only called when the mouse visibility actually changes */ - if (visible) { - CGDisplayShowCursor(kCGDirectMainDisplay); - } - else { - CGDisplayHideCursor(kCGDirectMainDisplay); - } -} - -_SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) { - if (lock == _sapp.mouse.locked) { - return; - } - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - _sapp.mouse.locked = lock; - /* - NOTE that this code doesn't warp the mouse cursor to the window - center as everybody else does it. This lead to a spike in the - *second* mouse-moved event after the warp happened. The - mouse centering doesn't seem to be required (mouse-moved events - are reported correctly even when the cursor is at an edge of the screen). - - NOTE also that the hide/show of the mouse cursor should properly - stack with calls to sapp_show_mouse() - */ - if (_sapp.mouse.locked) { - CGAssociateMouseAndMouseCursorPosition(NO); - [NSCursor hide]; - } - else { - [NSCursor unhide]; - CGAssociateMouseAndMouseCursorPosition(YES); - } -} - -_SOKOL_PRIVATE void _sapp_macos_update_cursor(sapp_mouse_cursor cursor, bool shown) { - // show/hide cursor only if visibility status has changed (required because show/hide stacks) - if (shown != _sapp.mouse.shown) { - if (shown) { - [NSCursor unhide]; - } - else { - [NSCursor hide]; - } - } - // update cursor type - SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM)); - if (_sapp.macos.cursors[cursor]) { - [_sapp.macos.cursors[cursor] set]; - } - else { - [[NSCursor arrowCursor] set]; - } -} - -_SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int num_images) { - NSDockTile* dock_tile = NSApp.dockTile; - const int wanted_width = (int) dock_tile.size.width; - const int wanted_height = (int) dock_tile.size.height; - const int img_index = _sapp_image_bestmatch(icon_desc->images, num_images, wanted_width, wanted_height); - const sapp_image_desc* img_desc = &icon_desc->images[img_index]; - - CGColorSpaceRef cg_color_space = CGColorSpaceCreateDeviceRGB(); - CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)img_desc->pixels.ptr, (CFIndex)img_desc->pixels.size); - CGDataProviderRef cg_data_provider = CGDataProviderCreateWithCFData(cf_data); - CGImageRef cg_img = CGImageCreate( - (size_t)img_desc->width, // width - (size_t)img_desc->height, // height - 8, // bitsPerComponent - 32, // bitsPerPixel - (size_t)img_desc->width * 4,// bytesPerRow - cg_color_space, // space - kCGImageAlphaLast | kCGImageByteOrderDefault, // bitmapInfo - cg_data_provider, // provider - NULL, // decode - false, // shouldInterpolate - kCGRenderingIntentDefault); - CFRelease(cf_data); - CGDataProviderRelease(cg_data_provider); - CGColorSpaceRelease(cg_color_space); - - NSImage* ns_image = [[NSImage alloc] initWithCGImage:cg_img size:dock_tile.size]; - dock_tile.contentView = [NSImageView imageViewWithImage:ns_image]; - [dock_tile display]; - _SAPP_OBJC_RELEASE(ns_image); - CGImageRelease(cg_img); -} - -_SOKOL_PRIVATE void _sapp_macos_frame(void) { - _sapp_frame(); - if (_sapp.quit_requested || _sapp.quit_ordered) { - [_sapp.macos.window performClose:nil]; - } -} - -@implementation _sapp_macos_app_delegate -- (void)applicationDidFinishLaunching:(NSNotification*)aNotification { - _SOKOL_UNUSED(aNotification); - _sapp_macos_init_cursors(); - if ((_sapp.window_width == 0) || (_sapp.window_height == 0)) { - // use 4/5 of screen size as default size - NSRect screen_rect = NSScreen.mainScreen.frame; - if (_sapp.window_width == 0) { - _sapp.window_width = (int)roundf((screen_rect.size.width * 4.0f) / 5.0f); - } - if (_sapp.window_height == 0) { - _sapp.window_height = (int)roundf((screen_rect.size.height * 4.0f) / 5.0f); - } - } - const NSUInteger style = - NSWindowStyleMaskTitled | - NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable | - NSWindowStyleMaskResizable; - NSRect window_rect = NSMakeRect(0, 0, _sapp.window_width, _sapp.window_height); - _sapp.macos.window = [[_sapp_macos_window alloc] - initWithContentRect:window_rect - styleMask:style - backing:NSBackingStoreBuffered - defer:NO]; - _sapp.macos.window.releasedWhenClosed = NO; // this is necessary for proper cleanup in applicationWillTerminate - _sapp.macos.window.title = [NSString stringWithUTF8String:_sapp.window_title]; - _sapp.macos.window.acceptsMouseMovedEvents = YES; - _sapp.macos.window.restorable = YES; - - _sapp.macos.win_dlg = [[_sapp_macos_window_delegate alloc] init]; - _sapp.macos.window.delegate = _sapp.macos.win_dlg; - #if defined(SOKOL_METAL) - NSInteger max_fps = 60; - #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 120000) - if (@available(macOS 12.0, *)) { - max_fps = [NSScreen.mainScreen maximumFramesPerSecond]; - } - #endif - _sapp.macos.mtl_device = MTLCreateSystemDefaultDevice(); - _sapp.macos.view = [[_sapp_macos_view alloc] init]; - [_sapp.macos.view updateTrackingAreas]; - _sapp.macos.view.preferredFramesPerSecond = max_fps / _sapp.swap_interval; - _sapp.macos.view.device = _sapp.macos.mtl_device; - _sapp.macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; - _sapp.macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - _sapp.macos.view.sampleCount = (NSUInteger) _sapp.sample_count; - _sapp.macos.view.autoResizeDrawable = false; - _sapp.macos.window.contentView = _sapp.macos.view; - [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; - _sapp.macos.view.layer.magnificationFilter = kCAFilterNearest; - #elif defined(SOKOL_GLCORE) - NSOpenGLPixelFormatAttribute attrs[32]; - int i = 0; - attrs[i++] = NSOpenGLPFAAccelerated; - attrs[i++] = NSOpenGLPFADoubleBuffer; - attrs[i++] = NSOpenGLPFAOpenGLProfile; - const int glVersion = _sapp.desc.gl_major_version * 10 + _sapp.desc.gl_minor_version; - switch(glVersion) { - case 10: attrs[i++] = NSOpenGLProfileVersionLegacy; break; - case 32: attrs[i++] = NSOpenGLProfileVersion3_2Core; break; - case 41: attrs[i++] = NSOpenGLProfileVersion4_1Core; break; - default: - _SAPP_PANIC(MACOS_INVALID_NSOPENGL_PROFILE); - } - attrs[i++] = NSOpenGLPFAColorSize; attrs[i++] = 24; - attrs[i++] = NSOpenGLPFAAlphaSize; attrs[i++] = 8; - attrs[i++] = NSOpenGLPFADepthSize; attrs[i++] = 24; - attrs[i++] = NSOpenGLPFAStencilSize; attrs[i++] = 8; - if (_sapp.sample_count > 1) { - attrs[i++] = NSOpenGLPFAMultisample; - attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 1; - attrs[i++] = NSOpenGLPFASamples; attrs[i++] = (NSOpenGLPixelFormatAttribute)_sapp.sample_count; - } - else { - attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 0; - } - attrs[i++] = 0; - NSOpenGLPixelFormat* glpixelformat_obj = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; - SOKOL_ASSERT(glpixelformat_obj != nil); - - _sapp.macos.view = [[_sapp_macos_view alloc] - initWithFrame:window_rect - pixelFormat:glpixelformat_obj]; - _SAPP_OBJC_RELEASE(glpixelformat_obj); - [_sapp.macos.view updateTrackingAreas]; - if (_sapp.desc.high_dpi) { - [_sapp.macos.view setWantsBestResolutionOpenGLSurface:YES]; - } - else { - [_sapp.macos.view setWantsBestResolutionOpenGLSurface:NO]; - } - - _sapp.macos.window.contentView = _sapp.macos.view; - [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; - - NSTimer* timer_obj = [NSTimer timerWithTimeInterval:0.001 - target:_sapp.macos.view - selector:@selector(timerFired:) - userInfo:nil - repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:timer_obj forMode:NSDefaultRunLoopMode]; - timer_obj = nil; - #endif - [_sapp.macos.window center]; - _sapp.valid = true; - if (_sapp.fullscreen) { - /* ^^^ on GL, this already toggles a rendered frame, so set the valid flag before */ - [_sapp.macos.window toggleFullScreen:self]; - } - NSApp.activationPolicy = NSApplicationActivationPolicyRegular; - [NSApp activateIgnoringOtherApps:YES]; - [_sapp.macos.window makeKeyAndOrderFront:nil]; - _sapp_macos_update_dimensions(); - [NSEvent setMouseCoalescingEnabled:NO]; - - // workaround for window not being focused during a long init callback - // for details see: https://github.com/floooh/sokol/pull/982 - // also see: https://gitlab.gnome.org/GNOME/gtk/-/issues/2342 - NSEvent *focusevent = [NSEvent otherEventWithType:NSEventTypeAppKitDefined - location:NSZeroPoint - modifierFlags:0x40 - timestamp:0 - windowNumber:0 - context:nil - subtype:NSEventSubtypeApplicationActivated - data1:0 - data2:0]; - [NSApp postEvent:focusevent atStart:YES]; -} - -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { - _SOKOL_UNUSED(sender); - return YES; -} - -- (void)applicationWillTerminate:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp_call_cleanup(); - _sapp_macos_discard_state(); - _sapp_discard_state(); -} -@end - -@implementation _sapp_macos_window_delegate -- (BOOL)windowShouldClose:(id)sender { - _SOKOL_UNUSED(sender); - /* only give user-code a chance to intervene when sapp_quit() wasn't already called */ - if (!_sapp.quit_ordered) { - /* if window should be closed and event handling is enabled, give user code - a chance to intervene via sapp_cancel_quit() - */ - _sapp.quit_requested = true; - _sapp_macos_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED); - /* user code hasn't intervened, quit the app */ - if (_sapp.quit_requested) { - _sapp.quit_ordered = true; - } - } - if (_sapp.quit_ordered) { - return YES; - } - else { - return NO; - } -} - -#if defined(SOKOL_METAL) -- (void)windowWillStartLiveResize:(NSNotification *)notification { - // Work around the MTKView resizing glitch by "anchoring" the layer to the window corner opposite - // to the currently manipulated corner (or edge). This prevents the content stretching back and - // forth during resizing. This is a workaround for this issue: https://github.com/floooh/sokol/issues/700 - // Can be removed if/when migrating to CAMetalLayer: https://github.com/floooh/sokol/issues/727 - bool resizing_from_left = _sapp.mouse.x < _sapp.window_width/2; - bool resizing_from_top = _sapp.mouse.y < _sapp.window_height/2; - NSViewLayerContentsPlacement placement; - if (resizing_from_left) { - placement = resizing_from_top ? NSViewLayerContentsPlacementBottomRight : NSViewLayerContentsPlacementTopRight; - } else { - placement = resizing_from_top ? NSViewLayerContentsPlacementBottomLeft : NSViewLayerContentsPlacementTopLeft; - } - _sapp.macos.view.layerContentsPlacement = placement; -} -#endif - -- (void)windowDidResize:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp_macos_update_dimensions(); -} - -- (void)windowDidChangeScreen:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp_timing_reset(&_sapp.timing); - _sapp_macos_update_dimensions(); -} - -- (void)windowDidMiniaturize:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp_macos_app_event(SAPP_EVENTTYPE_ICONIFIED); -} - -- (void)windowDidDeminiaturize:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp_macos_app_event(SAPP_EVENTTYPE_RESTORED); -} - -- (void)windowDidBecomeKey:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp_macos_app_event(SAPP_EVENTTYPE_FOCUSED); -} - -- (void)windowDidResignKey:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp_macos_app_event(SAPP_EVENTTYPE_UNFOCUSED); -} - -- (void)windowDidEnterFullScreen:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp.fullscreen = true; -} - -- (void)windowDidExitFullScreen:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp.fullscreen = false; -} -@end - -@implementation _sapp_macos_window -- (instancetype)initWithContentRect:(NSRect)contentRect - styleMask:(NSWindowStyleMask)style - backing:(NSBackingStoreType)backingStoreType - defer:(BOOL)flag { - if (self = [super initWithContentRect:contentRect styleMask:style backing:backingStoreType defer:flag]) { - #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 - [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]]; - #endif - } - return self; -} - -- (NSDragOperation)draggingEntered:(id)sender { - return NSDragOperationCopy; -} - -- (NSDragOperation)draggingUpdated:(id)sender { - return NSDragOperationCopy; -} - -- (BOOL)performDragOperation:(id)sender { - #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 - NSPasteboard *pboard = [sender draggingPasteboard]; - if ([pboard.types containsObject:NSPasteboardTypeFileURL]) { - _sapp_clear_drop_buffer(); - _sapp.drop.num_files = ((int)pboard.pasteboardItems.count > _sapp.drop.max_files) ? _sapp.drop.max_files : (int)pboard.pasteboardItems.count; - bool drop_failed = false; - for (int i = 0; i < _sapp.drop.num_files; i++) { - NSURL *fileUrl = [NSURL fileURLWithPath:[pboard.pasteboardItems[(NSUInteger)i] stringForType:NSPasteboardTypeFileURL]]; - if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { - _SAPP_ERROR(DROPPED_FILE_PATH_TOO_LONG); - drop_failed = true; - break; - } - } - if (!drop_failed) { - if (_sapp_events_enabled()) { - _sapp_macos_mouse_update_from_nspoint(sender.draggingLocation, true); - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); - _sapp.event.modifiers = _sapp_macos_mods(nil); - _sapp_call_event(&_sapp.event); - } - } - else { - _sapp_clear_drop_buffer(); - _sapp.drop.num_files = 0; - } - return YES; - } - #endif - return NO; -} -@end - -@implementation _sapp_macos_view -#if defined(SOKOL_GLCORE) -- (void)timerFired:(id)sender { - _SOKOL_UNUSED(sender); - [self setNeedsDisplay:YES]; -} -- (void)prepareOpenGL { - [super prepareOpenGL]; - GLint swapInt = 1; - NSOpenGLContext* ctx = [_sapp.macos.view openGLContext]; - [ctx setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval]; - [ctx makeCurrentContext]; -} -#endif - -_SOKOL_PRIVATE void _sapp_macos_poll_input_events(void) { - /* - - NOTE: late event polling temporarily out-commented to check if this - causes infrequent and almost impossible to reproduce problems with the - window close events, see: - https://github.com/floooh/sokol/pull/483#issuecomment-805148815 - - - const NSEventMask mask = NSEventMaskLeftMouseDown | - NSEventMaskLeftMouseUp| - NSEventMaskRightMouseDown | - NSEventMaskRightMouseUp | - NSEventMaskMouseMoved | - NSEventMaskLeftMouseDragged | - NSEventMaskRightMouseDragged | - NSEventMaskMouseEntered | - NSEventMaskMouseExited | - NSEventMaskKeyDown | - NSEventMaskKeyUp | - NSEventMaskCursorUpdate | - NSEventMaskScrollWheel | - NSEventMaskTabletPoint | - NSEventMaskTabletProximity | - NSEventMaskOtherMouseDown | - NSEventMaskOtherMouseUp | - NSEventMaskOtherMouseDragged | - NSEventMaskPressure | - NSEventMaskDirectTouch; - @autoreleasepool { - for (;;) { - // NOTE: using NSDefaultRunLoopMode here causes stuttering in the GL backend, - // see: https://github.com/floooh/sokol/issues/486 - NSEvent* event = [NSApp nextEventMatchingMask:mask untilDate:nil inMode:NSEventTrackingRunLoopMode dequeue:YES]; - if (event == nil) { - break; - } - [NSApp sendEvent:event]; - } - } - */ -} - -- (void)drawRect:(NSRect)rect { - _SOKOL_UNUSED(rect); - #if defined(_SAPP_ANY_GL) - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); - #endif - _sapp_timing_measure(&_sapp.timing); - /* Catch any last-moment input events */ - _sapp_macos_poll_input_events(); - @autoreleasepool { - _sapp_macos_frame(); - } - #if defined(_SAPP_ANY_GL) - [[_sapp.macos.view openGLContext] flushBuffer]; - #endif -} - -- (BOOL)isOpaque { - return YES; -} -- (BOOL)canBecomeKeyView { - return YES; -} -- (BOOL)acceptsFirstResponder { - return YES; -} -- (void)updateTrackingAreas { - if (_sapp.macos.tracking_area != nil) { - [self removeTrackingArea:_sapp.macos.tracking_area]; - _SAPP_OBJC_RELEASE(_sapp.macos.tracking_area); - } - const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | - NSTrackingActiveInKeyWindow | - NSTrackingEnabledDuringMouseDrag | - NSTrackingCursorUpdate | - NSTrackingInVisibleRect | - NSTrackingAssumeInside; - _sapp.macos.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; - [self addTrackingArea:_sapp.macos.tracking_area]; - [super updateTrackingAreas]; -} - -// helper function to make GL context active -static void _sapp_gl_make_current(void) { - #if defined(SOKOL_GLCORE) - [[_sapp.macos.view openGLContext] makeCurrentContext]; - #endif -} - -- (void)mouseEntered:(NSEvent*)event { - _sapp_gl_make_current(); - _sapp_macos_mouse_update_from_nsevent(event, true); - /* don't send mouse enter/leave while dragging (so that it behaves the same as - on Windows while SetCapture is active - */ - if (0 == _sapp.macos.mouse_buttons) { - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); - } -} -- (void)mouseExited:(NSEvent*)event { - _sapp_gl_make_current(); - _sapp_macos_mouse_update_from_nsevent(event, true); - if (0 == _sapp.macos.mouse_buttons) { - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); - } -} -- (void)mouseDown:(NSEvent*)event { - _sapp_gl_make_current(); - _sapp_macos_mouse_update_from_nsevent(event, false); - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mods(event)); - _sapp.macos.mouse_buttons |= (1< 0.0f) || (_sapp_absf(dy) > 0.0f)) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); - _sapp.event.modifiers = _sapp_macos_mods(event); - _sapp.event.scroll_x = dx; - _sapp.event.scroll_y = dy; - _sapp_call_event(&_sapp.event); - } - } -} -- (void)keyDown:(NSEvent*)event { - if (_sapp_events_enabled()) { - _sapp_gl_make_current(); - const uint32_t mods = _sapp_macos_mods(event); - const sapp_keycode key_code = _sapp_translate_key(event.keyCode); - _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_DOWN, key_code, event.isARepeat, mods); - const NSString* chars = event.characters; - const NSUInteger len = chars.length; - if (len > 0) { - _sapp_init_event(SAPP_EVENTTYPE_CHAR); - _sapp.event.modifiers = mods; - for (NSUInteger i = 0; i < len; i++) { - const unichar codepoint = [chars characterAtIndex:i]; - if ((codepoint & 0xFF00) == 0xF700) { - continue; - } - _sapp.event.char_code = codepoint; - _sapp.event.key_repeat = event.isARepeat; - _sapp_call_event(&_sapp.event); - } - } - /* if this is a Cmd+V (paste), also send a CLIPBOARD_PASTE event */ - if (_sapp.clipboard.enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); - _sapp_call_event(&_sapp.event); - } - } -} -- (void)keyUp:(NSEvent*)event { - _sapp_gl_make_current(); - _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_UP, - _sapp_translate_key(event.keyCode), - event.isARepeat, - _sapp_macos_mods(event)); -} -- (void)flagsChanged:(NSEvent*)event { - const uint32_t old_f = _sapp.macos.flags_changed_store; - const uint32_t new_f = (uint32_t)event.modifierFlags; - _sapp.macos.flags_changed_store = new_f; - sapp_keycode key_code = SAPP_KEYCODE_INVALID; - bool down = false; - if ((new_f ^ old_f) & NSEventModifierFlagShift) { - key_code = SAPP_KEYCODE_LEFT_SHIFT; - down = 0 != (new_f & NSEventModifierFlagShift); - } - if ((new_f ^ old_f) & NSEventModifierFlagControl) { - key_code = SAPP_KEYCODE_LEFT_CONTROL; - down = 0 != (new_f & NSEventModifierFlagControl); - } - if ((new_f ^ old_f) & NSEventModifierFlagOption) { - key_code = SAPP_KEYCODE_LEFT_ALT; - down = 0 != (new_f & NSEventModifierFlagOption); - } - if ((new_f ^ old_f) & NSEventModifierFlagCommand) { - key_code = SAPP_KEYCODE_LEFT_SUPER; - down = 0 != (new_f & NSEventModifierFlagCommand); - } - if (key_code != SAPP_KEYCODE_INVALID) { - _sapp_macos_key_event(down ? SAPP_EVENTTYPE_KEY_DOWN : SAPP_EVENTTYPE_KEY_UP, - key_code, - false, - _sapp_macos_mods(event)); - } -} -@end - -#endif // macOS - -// ██ ██████ ███████ -// ██ ██ ██ ██ -// ██ ██ ██ ███████ -// ██ ██ ██ ██ -// ██ ██████ ███████ -// -// >>ios -#if defined(_SAPP_IOS) - -_SOKOL_PRIVATE void _sapp_ios_discard_state(void) { - // NOTE: it's safe to call [release] on a nil object - _SAPP_OBJC_RELEASE(_sapp.ios.textfield_dlg); - _SAPP_OBJC_RELEASE(_sapp.ios.textfield); - #if defined(SOKOL_METAL) - _SAPP_OBJC_RELEASE(_sapp.ios.view_ctrl); - _SAPP_OBJC_RELEASE(_sapp.ios.mtl_device); - #else - _SAPP_OBJC_RELEASE(_sapp.ios.view_ctrl); - _SAPP_OBJC_RELEASE(_sapp.ios.eagl_ctx); - #endif - _SAPP_OBJC_RELEASE(_sapp.ios.view); - _SAPP_OBJC_RELEASE(_sapp.ios.window); -} - -_SOKOL_PRIVATE void _sapp_ios_run(const sapp_desc* desc) { - _sapp_init_state(desc); - static int argc = 1; - static char* argv[] = { (char*)"sokol_app" }; - UIApplicationMain(argc, argv, nil, NSStringFromClass([_sapp_app_delegate class])); -} - -/* iOS entry function */ -#if !defined(SOKOL_NO_ENTRY) -int main(int argc, char* argv[]) { - sapp_desc desc = sokol_main(argc, argv); - _sapp_ios_run(&desc); - return 0; -} -#endif /* SOKOL_NO_ENTRY */ - -_SOKOL_PRIVATE void _sapp_ios_app_event(sapp_event_type type) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_ios_touch_event(sapp_event_type type, NSSet* touches, UIEvent* event) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - NSEnumerator* enumerator = event.allTouches.objectEnumerator; - UITouch* ios_touch; - while ((ios_touch = [enumerator nextObject])) { - if ((_sapp.event.num_touches + 1) < SAPP_MAX_TOUCHPOINTS) { - CGPoint ios_pos = [ios_touch locationInView:_sapp.ios.view]; - sapp_touchpoint* cur_point = &_sapp.event.touches[_sapp.event.num_touches++]; - cur_point->identifier = (uintptr_t) ios_touch; - cur_point->pos_x = ios_pos.x * _sapp.dpi_scale; - cur_point->pos_y = ios_pos.y * _sapp.dpi_scale; - cur_point->changed = [touches containsObject:ios_touch]; - } - } - if (_sapp.event.num_touches > 0) { - _sapp_call_event(&_sapp.event); - } - } -} - -_SOKOL_PRIVATE void _sapp_ios_update_dimensions(void) { - CGRect screen_rect = UIScreen.mainScreen.bounds; - _sapp.framebuffer_width = (int)roundf(screen_rect.size.width * _sapp.dpi_scale); - _sapp.framebuffer_height = (int)roundf(screen_rect.size.height * _sapp.dpi_scale); - _sapp.window_width = (int)roundf(screen_rect.size.width); - _sapp.window_height = (int)roundf(screen_rect.size.height); - int cur_fb_width, cur_fb_height; - #if defined(SOKOL_METAL) - const CGSize fb_size = _sapp.ios.view.drawableSize; - cur_fb_width = (int)roundf(fb_size.width); - cur_fb_height = (int)roundf(fb_size.height); - #else - cur_fb_width = (int)roundf(_sapp.ios.view.drawableWidth); - cur_fb_height = (int)roundf(_sapp.ios.view.drawableHeight); - #endif - const bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || - (_sapp.framebuffer_height != cur_fb_height); - if (dim_changed) { - #if defined(SOKOL_METAL) - const CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height }; - _sapp.ios.view.drawableSize = drawable_size; - #else - // nothing to do here, GLKView correctly respects the view's contentScaleFactor - #endif - if (!_sapp.first_frame) { - _sapp_ios_app_event(SAPP_EVENTTYPE_RESIZED); - } - } -} - -_SOKOL_PRIVATE void _sapp_ios_frame(void) { - _sapp_ios_update_dimensions(); - _sapp_frame(); -} - -_SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { - /* if not happened yet, create an invisible text field */ - if (nil == _sapp.ios.textfield) { - _sapp.ios.textfield_dlg = [[_sapp_textfield_dlg alloc] init]; - _sapp.ios.textfield = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 100, 50)]; - _sapp.ios.textfield.keyboardType = UIKeyboardTypeDefault; - _sapp.ios.textfield.returnKeyType = UIReturnKeyDefault; - _sapp.ios.textfield.autocapitalizationType = UITextAutocapitalizationTypeNone; - _sapp.ios.textfield.autocorrectionType = UITextAutocorrectionTypeNo; - _sapp.ios.textfield.spellCheckingType = UITextSpellCheckingTypeNo; - _sapp.ios.textfield.hidden = YES; - _sapp.ios.textfield.text = @"x"; - _sapp.ios.textfield.delegate = _sapp.ios.textfield_dlg; - [_sapp.ios.view_ctrl.view addSubview:_sapp.ios.textfield]; - - [[NSNotificationCenter defaultCenter] addObserver:_sapp.ios.textfield_dlg - selector:@selector(keyboardWasShown:) - name:UIKeyboardDidShowNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:_sapp.ios.textfield_dlg - selector:@selector(keyboardWillBeHidden:) - name:UIKeyboardWillHideNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:_sapp.ios.textfield_dlg - selector:@selector(keyboardDidChangeFrame:) - name:UIKeyboardDidChangeFrameNotification object:nil]; - } - if (shown) { - /* setting the text field as first responder brings up the onscreen keyboard */ - [_sapp.ios.textfield becomeFirstResponder]; - } - else { - [_sapp.ios.textfield resignFirstResponder]; - } -} - -@implementation _sapp_app_delegate -- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { - CGRect screen_rect = UIScreen.mainScreen.bounds; - _sapp.ios.window = [[UIWindow alloc] initWithFrame:screen_rect]; - _sapp.window_width = (int)roundf(screen_rect.size.width); - _sapp.window_height = (int)roundf(screen_rect.size.height); - if (_sapp.desc.high_dpi) { - _sapp.dpi_scale = (float) UIScreen.mainScreen.nativeScale; - } - else { - _sapp.dpi_scale = 1.0f; - } - _sapp.framebuffer_width = (int)roundf(_sapp.window_width * _sapp.dpi_scale); - _sapp.framebuffer_height = (int)roundf(_sapp.window_height * _sapp.dpi_scale); - NSInteger max_fps = UIScreen.mainScreen.maximumFramesPerSecond; - #if defined(SOKOL_METAL) - _sapp.ios.mtl_device = MTLCreateSystemDefaultDevice(); - _sapp.ios.view = [[_sapp_ios_view alloc] init]; - _sapp.ios.view.preferredFramesPerSecond = max_fps / _sapp.swap_interval; - _sapp.ios.view.device = _sapp.ios.mtl_device; - _sapp.ios.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; - _sapp.ios.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - _sapp.ios.view.sampleCount = (NSUInteger)_sapp.sample_count; - /* NOTE: iOS MTKView seems to ignore thew view's contentScaleFactor - and automatically renders at Retina resolution. We'll disable - autoResize and instead do the resizing in _sapp_ios_update_dimensions() - */ - _sapp.ios.view.autoResizeDrawable = false; - _sapp.ios.view.userInteractionEnabled = YES; - _sapp.ios.view.multipleTouchEnabled = YES; - _sapp.ios.view_ctrl = [[UIViewController alloc] init]; - _sapp.ios.view_ctrl.modalPresentationStyle = UIModalPresentationFullScreen; - _sapp.ios.view_ctrl.view = _sapp.ios.view; - _sapp.ios.window.rootViewController = _sapp.ios.view_ctrl; - #else - _sapp.ios.eagl_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; - _sapp.ios.view = [[_sapp_ios_view alloc] initWithFrame:screen_rect]; - _sapp.ios.view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888; - _sapp.ios.view.drawableDepthFormat = GLKViewDrawableDepthFormat24; - _sapp.ios.view.drawableStencilFormat = GLKViewDrawableStencilFormatNone; - GLKViewDrawableMultisample msaa = _sapp.sample_count > 1 ? GLKViewDrawableMultisample4X : GLKViewDrawableMultisampleNone; - _sapp.ios.view.drawableMultisample = msaa; - _sapp.ios.view.context = _sapp.ios.eagl_ctx; - _sapp.ios.view.enableSetNeedsDisplay = NO; - _sapp.ios.view.userInteractionEnabled = YES; - _sapp.ios.view.multipleTouchEnabled = YES; - // on GLKView, contentScaleFactor appears to work just fine! - if (_sapp.desc.high_dpi) { - _sapp.ios.view.contentScaleFactor = _sapp.dpi_scale; - } - else { - _sapp.ios.view.contentScaleFactor = 1.0; - } - _sapp.ios.view_ctrl = [[GLKViewController alloc] init]; - _sapp.ios.view_ctrl.view = _sapp.ios.view; - _sapp.ios.view_ctrl.preferredFramesPerSecond = max_fps / _sapp.swap_interval; - _sapp.ios.window.rootViewController = _sapp.ios.view_ctrl; - #endif - [_sapp.ios.window makeKeyAndVisible]; - - _sapp.valid = true; - return YES; -} - -- (void)applicationWillResignActive:(UIApplication *)application { - if (!_sapp.ios.suspended) { - _sapp.ios.suspended = true; - _sapp_ios_app_event(SAPP_EVENTTYPE_SUSPENDED); - } -} - -- (void)applicationDidBecomeActive:(UIApplication *)application { - if (_sapp.ios.suspended) { - _sapp.ios.suspended = false; - _sapp_ios_app_event(SAPP_EVENTTYPE_RESUMED); - } -} - -/* NOTE: this method will rarely ever be called, iOS application - which are terminated by the user are usually killed via signal 9 - by the operating system. -*/ -- (void)applicationWillTerminate:(UIApplication *)application { - _SOKOL_UNUSED(application); - _sapp_call_cleanup(); - _sapp_ios_discard_state(); - _sapp_discard_state(); -} -@end - -@implementation _sapp_textfield_dlg -- (void)keyboardWasShown:(NSNotification*)notif { - _sapp.onscreen_keyboard_shown = true; - /* query the keyboard's size, and modify the content view's size */ - if (_sapp.desc.ios_keyboard_resizes_canvas) { - NSDictionary* info = notif.userInfo; - CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; - CGRect view_frame = UIScreen.mainScreen.bounds; - view_frame.size.height -= kbd_h; - _sapp.ios.view.frame = view_frame; - } -} -- (void)keyboardWillBeHidden:(NSNotification*)notif { - _sapp.onscreen_keyboard_shown = false; - if (_sapp.desc.ios_keyboard_resizes_canvas) { - _sapp.ios.view.frame = UIScreen.mainScreen.bounds; - } -} -- (void)keyboardDidChangeFrame:(NSNotification*)notif { - /* this is for the case when the screen rotation changes while the keyboard is open */ - if (_sapp.onscreen_keyboard_shown && _sapp.desc.ios_keyboard_resizes_canvas) { - NSDictionary* info = notif.userInfo; - CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; - CGRect view_frame = UIScreen.mainScreen.bounds; - view_frame.size.height -= kbd_h; - _sapp.ios.view.frame = view_frame; - } -} -- (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string { - if (_sapp_events_enabled()) { - const NSUInteger len = string.length; - if (len > 0) { - for (NSUInteger i = 0; i < len; i++) { - unichar c = [string characterAtIndex:i]; - if (c >= 32) { - /* ignore surrogates for now */ - if ((c < 0xD800) || (c > 0xDFFF)) { - _sapp_init_event(SAPP_EVENTTYPE_CHAR); - _sapp.event.char_code = c; - _sapp_call_event(&_sapp.event); - } - } - if (c <= 32) { - sapp_keycode k = SAPP_KEYCODE_INVALID; - switch (c) { - case 10: k = SAPP_KEYCODE_ENTER; break; - case 32: k = SAPP_KEYCODE_SPACE; break; - default: break; - } - if (k != SAPP_KEYCODE_INVALID) { - _sapp_init_event(SAPP_EVENTTYPE_KEY_DOWN); - _sapp.event.key_code = k; - _sapp_call_event(&_sapp.event); - _sapp_init_event(SAPP_EVENTTYPE_KEY_UP); - _sapp.event.key_code = k; - _sapp_call_event(&_sapp.event); - } - } - } - } - else { - /* this was a backspace */ - _sapp_init_event(SAPP_EVENTTYPE_KEY_DOWN); - _sapp.event.key_code = SAPP_KEYCODE_BACKSPACE; - _sapp_call_event(&_sapp.event); - _sapp_init_event(SAPP_EVENTTYPE_KEY_UP); - _sapp.event.key_code = SAPP_KEYCODE_BACKSPACE; - _sapp_call_event(&_sapp.event); - } - } - return NO; -} -@end - -@implementation _sapp_ios_view -- (void)drawRect:(CGRect)rect { - _SOKOL_UNUSED(rect); - #if defined(_SAPP_ANY_GL) - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); - #endif - _sapp_timing_measure(&_sapp.timing); - @autoreleasepool { - _sapp_ios_frame(); - } -} -- (BOOL)isOpaque { - return YES; -} -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event { - _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_BEGAN, touches, event); -} -- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent*)event { - _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_MOVED, touches, event); -} -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent*)event { - _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_ENDED, touches, event); -} -- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent*)event { - _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_CANCELLED, touches, event); -} -@end -#endif /* TARGET_OS_IPHONE */ - -#endif /* _SAPP_APPLE */ - -// ███████ ███ ███ ███████ ██████ ██████ ██ ██████ ████████ ███████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// █████ ██ ████ ██ ███████ ██ ██████ ██ ██████ ██ █████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ███████ ██████ ██ ██ ██ ██ ██ ███████ ██ ████ -// -// >>emscripten -#if defined(_SAPP_EMSCRIPTEN) - -#if defined(EM_JS_DEPS) -EM_JS_DEPS(sokol_app, "$withStackSave,$stringToUTF8OnStack"); -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*_sapp_html5_fetch_callback) (const sapp_html5_fetch_response*); - -EMSCRIPTEN_KEEPALIVE void _sapp_emsc_onpaste(const char* str) { - if (_sapp.clipboard.enabled) { - _sapp_strcpy(str, _sapp.clipboard.buffer, _sapp.clipboard.buf_size); - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); - _sapp_call_event(&_sapp.event); - } - } -} - -/* https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload */ -EMSCRIPTEN_KEEPALIVE int _sapp_html5_get_ask_leave_site(void) { - return _sapp.html5_ask_leave_site ? 1 : 0; -} - -EMSCRIPTEN_KEEPALIVE void _sapp_emsc_begin_drop(int num) { - if (!_sapp.drop.enabled) { - return; - } - if (num < 0) { - num = 0; - } - if (num > _sapp.drop.max_files) { - num = _sapp.drop.max_files; - } - _sapp.drop.num_files = num; - _sapp_clear_drop_buffer(); -} - -EMSCRIPTEN_KEEPALIVE void _sapp_emsc_drop(int i, const char* name) { - /* NOTE: name is only the filename part, not a path */ - if (!_sapp.drop.enabled) { - return; - } - if (0 == name) { - return; - } - SOKOL_ASSERT(_sapp.drop.num_files <= _sapp.drop.max_files); - if ((i < 0) || (i >= _sapp.drop.num_files)) { - return; - } - if (!_sapp_strcpy(name, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { - _SAPP_ERROR(DROPPED_FILE_PATH_TOO_LONG); - _sapp.drop.num_files = 0; - } -} - -EMSCRIPTEN_KEEPALIVE void _sapp_emsc_end_drop(int x, int y, int mods) { - if (!_sapp.drop.enabled) { - return; - } - if (0 == _sapp.drop.num_files) { - /* there was an error copying the filenames */ - _sapp_clear_drop_buffer(); - return; - - } - if (_sapp_events_enabled()) { - _sapp.mouse.x = (float)x * _sapp.dpi_scale; - _sapp.mouse.y = (float)y * _sapp.dpi_scale; - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); - // see sapp_js_add_dragndrop_listeners for mods constants - if (mods & 1) { _sapp.event.modifiers |= SAPP_MODIFIER_SHIFT; } - if (mods & 2) { _sapp.event.modifiers |= SAPP_MODIFIER_CTRL; } - if (mods & 4) { _sapp.event.modifiers |= SAPP_MODIFIER_ALT; } - if (mods & 8) { _sapp.event.modifiers |= SAPP_MODIFIER_SUPER; } - _sapp_call_event(&_sapp.event); - } -} - -EMSCRIPTEN_KEEPALIVE void _sapp_emsc_invoke_fetch_cb(int index, int success, int error_code, _sapp_html5_fetch_callback callback, uint32_t fetched_size, void* buf_ptr, uint32_t buf_size, void* user_data) { - sapp_html5_fetch_response response; - _sapp_clear(&response, sizeof(response)); - response.succeeded = (0 != success); - response.error_code = (sapp_html5_fetch_error) error_code; - response.file_index = index; - response.data.ptr = buf_ptr; - response.data.size = fetched_size; - response.buffer.ptr = buf_ptr; - response.buffer.size = buf_size; - response.user_data = user_data; - callback(&response); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -EM_JS(void, sapp_js_add_beforeunload_listener, (void), { - Module.sokol_beforeunload = (event) => { - if (__sapp_html5_get_ask_leave_site() != 0) { - event.preventDefault(); - event.returnValue = ' '; - } - }; - window.addEventListener('beforeunload', Module.sokol_beforeunload); -}); - -EM_JS(void, sapp_js_remove_beforeunload_listener, (void), { - window.removeEventListener('beforeunload', Module.sokol_beforeunload); -}); - -EM_JS(void, sapp_js_add_clipboard_listener, (void), { - Module.sokol_paste = (event) => { - const pasted_str = event.clipboardData.getData('text'); - withStackSave(() => { - const cstr = stringToUTF8OnStack(pasted_str); - __sapp_emsc_onpaste(cstr); - }); - }; - window.addEventListener('paste', Module.sokol_paste); -}); - -EM_JS(void, sapp_js_remove_clipboard_listener, (void), { - window.removeEventListener('paste', Module.sokol_paste); -}); - -EM_JS(void, sapp_js_write_clipboard, (const char* c_str), { - const str = UTF8ToString(c_str); - const ta = document.createElement('textarea'); - ta.setAttribute('autocomplete', 'off'); - ta.setAttribute('autocorrect', 'off'); - ta.setAttribute('autocapitalize', 'off'); - ta.setAttribute('spellcheck', 'false'); - ta.style.left = -100 + 'px'; - ta.style.top = -100 + 'px'; - ta.style.height = 1; - ta.style.width = 1; - ta.value = str; - document.body.appendChild(ta); - ta.select(); - document.execCommand('copy'); - document.body.removeChild(ta); -}); - -_SOKOL_PRIVATE void _sapp_emsc_set_clipboard_string(const char* str) { - sapp_js_write_clipboard(str); -} - -EM_JS(void, sapp_js_add_dragndrop_listeners, (const char* canvas_name_cstr), { - Module.sokol_drop_files = []; - const canvas_name = UTF8ToString(canvas_name_cstr); - const canvas = document.getElementById(canvas_name); - Module.sokol_dragenter = (event) => { - event.stopPropagation(); - event.preventDefault(); - }; - Module.sokol_dragleave = (event) => { - event.stopPropagation(); - event.preventDefault(); - }; - Module.sokol_dragover = (event) => { - event.stopPropagation(); - event.preventDefault(); - }; - Module.sokol_drop = (event) => { - event.stopPropagation(); - event.preventDefault(); - const files = event.dataTransfer.files; - Module.sokol_dropped_files = files; - __sapp_emsc_begin_drop(files.length); - for (let i = 0; i < files.length; i++) { - withStackSave(() => { - const cstr = stringToUTF8OnStack(files[i].name); - __sapp_emsc_drop(i, cstr); - }); - } - let mods = 0; - if (event.shiftKey) { mods |= 1; } - if (event.ctrlKey) { mods |= 2; } - if (event.altKey) { mods |= 4; } - if (event.metaKey) { mods |= 8; } - // FIXME? see computation of targetX/targetY in emscripten via getClientBoundingRect - __sapp_emsc_end_drop(event.clientX, event.clientY, mods); - }; - canvas.addEventListener('dragenter', Module.sokol_dragenter, false); - canvas.addEventListener('dragleave', Module.sokol_dragleave, false); - canvas.addEventListener('dragover', Module.sokol_dragover, false); - canvas.addEventListener('drop', Module.sokol_drop, false); -}); - -EM_JS(uint32_t, sapp_js_dropped_file_size, (int index), { - \x2F\x2A\x2A @suppress {missingProperties} \x2A\x2F - const files = Module.sokol_dropped_files; - if ((index < 0) || (index >= files.length)) { - return 0; - } - else { - return files[index].size; - } -}); - -EM_JS(void, sapp_js_fetch_dropped_file, (int index, _sapp_html5_fetch_callback callback, void* buf_ptr, uint32_t buf_size, void* user_data), { - const reader = new FileReader(); - reader.onload = (loadEvent) => { - const content = loadEvent.target.result; - if (content.byteLength > buf_size) { - // SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL - __sapp_emsc_invoke_fetch_cb(index, 0, 1, callback, 0, buf_ptr, buf_size, user_data); - } - else { - HEAPU8.set(new Uint8Array(content), buf_ptr); - __sapp_emsc_invoke_fetch_cb(index, 1, 0, callback, content.byteLength, buf_ptr, buf_size, user_data); - } - }; - reader.onerror = () => { - // SAPP_HTML5_FETCH_ERROR_OTHER - __sapp_emsc_invoke_fetch_cb(index, 0, 2, callback, 0, buf_ptr, buf_size, user_data); - }; - \x2F\x2A\x2A @suppress {missingProperties} \x2A\x2F - const files = Module.sokol_dropped_files; - reader.readAsArrayBuffer(files[index]); -}); - -EM_JS(void, sapp_js_remove_dragndrop_listeners, (const char* canvas_name_cstr), { - const canvas_name = UTF8ToString(canvas_name_cstr); - const canvas = document.getElementById(canvas_name); - canvas.removeEventListener('dragenter', Module.sokol_dragenter); - canvas.removeEventListener('dragleave', Module.sokol_dragleave); - canvas.removeEventListener('dragover', Module.sokol_dragover); - canvas.removeEventListener('drop', Module.sokol_drop); -}); - -EM_JS(void, sapp_js_init, (const char* c_str_target), { - // lookup and store canvas object by name - const target_str = UTF8ToString(c_str_target); - Module.sapp_emsc_target = document.getElementById(target_str); - if (!Module.sapp_emsc_target) { - console.log("sokol_app.h: invalid target:" + target_str); - } - if (!Module.sapp_emsc_target.requestPointerLock) { - console.log("sokol_app.h: target doesn't support requestPointerLock:" + target_str); - } -}); - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_pointerlockchange_cb(int emsc_type, const EmscriptenPointerlockChangeEvent* emsc_event, void* user_data) { - _SOKOL_UNUSED(emsc_type); - _SOKOL_UNUSED(user_data); - _sapp.mouse.locked = emsc_event->isActive; - return EM_TRUE; -} - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_pointerlockerror_cb(int emsc_type, const void* reserved, void* user_data) { - _SOKOL_UNUSED(emsc_type); - _SOKOL_UNUSED(reserved); - _SOKOL_UNUSED(user_data); - _sapp.mouse.locked = false; - _sapp.emsc.mouse_lock_requested = false; - return true; -} - -EM_JS(void, sapp_js_request_pointerlock, (void), { - if (Module.sapp_emsc_target) { - if (Module.sapp_emsc_target.requestPointerLock) { - Module.sapp_emsc_target.requestPointerLock(); - } - } -}); - -EM_JS(void, sapp_js_exit_pointerlock, (void), { - if (document.exitPointerLock) { - document.exitPointerLock(); - } -}); - -_SOKOL_PRIVATE void _sapp_emsc_lock_mouse(bool lock) { - if (lock) { - /* request mouse-lock during event handler invocation (see _sapp_emsc_update_mouse_lock_state) */ - _sapp.emsc.mouse_lock_requested = true; - } - else { - /* NOTE: the _sapp.mouse_locked state will be set in the pointerlockchange callback */ - _sapp.emsc.mouse_lock_requested = false; - sapp_js_exit_pointerlock(); - } -} - -/* called from inside event handlers to check if mouse lock had been requested, - and if yes, actually enter mouse lock. -*/ -_SOKOL_PRIVATE void _sapp_emsc_update_mouse_lock_state(void) { - if (_sapp.emsc.mouse_lock_requested) { - _sapp.emsc.mouse_lock_requested = false; - sapp_js_request_pointerlock(); - } -} - -// set mouse cursor type -EM_JS(void, sapp_js_set_cursor, (int cursor_type, int shown), { - if (Module.sapp_emsc_target) { - let cursor; - if (shown === 0) { - cursor = "none"; - } - else switch (cursor_type) { - case 0: cursor = "auto"; break; // SAPP_MOUSECURSOR_DEFAULT - case 1: cursor = "default"; break; // SAPP_MOUSECURSOR_ARROW - case 2: cursor = "text"; break; // SAPP_MOUSECURSOR_IBEAM - case 3: cursor = "crosshair"; break; // SAPP_MOUSECURSOR_CROSSHAIR - case 4: cursor = "pointer"; break; // SAPP_MOUSECURSOR_POINTING_HAND - case 5: cursor = "ew-resize"; break; // SAPP_MOUSECURSOR_RESIZE_EW - case 6: cursor = "ns-resize"; break; // SAPP_MOUSECURSOR_RESIZE_NS - case 7: cursor = "nwse-resize"; break; // SAPP_MOUSECURSOR_RESIZE_NWSE - case 8: cursor = "nesw-resize"; break; // SAPP_MOUSECURSOR_RESIZE_NESW - case 9: cursor = "all-scroll"; break; // SAPP_MOUSECURSOR_RESIZE_ALL - case 10: cursor = "not-allowed"; break; // SAPP_MOUSECURSOR_NOT_ALLOWED - default: cursor = "auto"; break; - } - Module.sapp_emsc_target.style.cursor = cursor; - } -}); - -_SOKOL_PRIVATE void _sapp_emsc_update_cursor(sapp_mouse_cursor cursor, bool shown) { - SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM)); - sapp_js_set_cursor((int)cursor, shown ? 1 : 0); -} - -/* JS helper functions to update browser tab favicon */ -EM_JS(void, sapp_js_clear_favicon, (void), { - const link = document.getElementById('sokol-app-favicon'); - if (link) { - document.head.removeChild(link); - } -}); - -EM_JS(void, sapp_js_set_favicon, (int w, int h, const uint8_t* pixels), { - const canvas = document.createElement('canvas'); - canvas.width = w; - canvas.height = h; - const ctx = canvas.getContext('2d'); - const img_data = ctx.createImageData(w, h); - img_data.data.set(HEAPU8.subarray(pixels, pixels + w*h*4)); - ctx.putImageData(img_data, 0, 0); - const new_link = document.createElement('link'); - new_link.id = 'sokol-app-favicon'; - new_link.rel = 'shortcut icon'; - new_link.href = canvas.toDataURL(); - document.head.appendChild(new_link); -}); - -_SOKOL_PRIVATE void _sapp_emsc_set_icon(const sapp_icon_desc* icon_desc, int num_images) { - SOKOL_ASSERT((num_images > 0) && (num_images <= SAPP_MAX_ICONIMAGES)); - sapp_js_clear_favicon(); - // find the best matching image candidate for 16x16 pixels - int img_index = _sapp_image_bestmatch(icon_desc->images, num_images, 16, 16); - const sapp_image_desc* img_desc = &icon_desc->images[img_index]; - sapp_js_set_favicon(img_desc->width, img_desc->height, (const uint8_t*) img_desc->pixels.ptr); -} - -_SOKOL_PRIVATE uint32_t _sapp_emsc_mouse_button_mods(uint16_t buttons) { - uint32_t m = 0; - if (0 != (buttons & (1<<0))) { m |= SAPP_MODIFIER_LMB; } - if (0 != (buttons & (1<<1))) { m |= SAPP_MODIFIER_RMB; } // not a bug - if (0 != (buttons & (1<<2))) { m |= SAPP_MODIFIER_MMB; } // not a bug - return m; -} - -_SOKOL_PRIVATE uint32_t _sapp_emsc_mouse_event_mods(const EmscriptenMouseEvent* ev) { - uint32_t m = 0; - if (ev->ctrlKey) { m |= SAPP_MODIFIER_CTRL; } - if (ev->shiftKey) { m |= SAPP_MODIFIER_SHIFT; } - if (ev->altKey) { m |= SAPP_MODIFIER_ALT; } - if (ev->metaKey) { m |= SAPP_MODIFIER_SUPER; } - m |= _sapp_emsc_mouse_button_mods(_sapp.emsc.mouse_buttons); - return m; -} - -_SOKOL_PRIVATE uint32_t _sapp_emsc_key_event_mods(const EmscriptenKeyboardEvent* ev) { - uint32_t m = 0; - if (ev->ctrlKey) { m |= SAPP_MODIFIER_CTRL; } - if (ev->shiftKey) { m |= SAPP_MODIFIER_SHIFT; } - if (ev->altKey) { m |= SAPP_MODIFIER_ALT; } - if (ev->metaKey) { m |= SAPP_MODIFIER_SUPER; } - m |= _sapp_emsc_mouse_button_mods(_sapp.emsc.mouse_buttons); - return m; -} - -_SOKOL_PRIVATE uint32_t _sapp_emsc_touch_event_mods(const EmscriptenTouchEvent* ev) { - uint32_t m = 0; - if (ev->ctrlKey) { m |= SAPP_MODIFIER_CTRL; } - if (ev->shiftKey) { m |= SAPP_MODIFIER_SHIFT; } - if (ev->altKey) { m |= SAPP_MODIFIER_ALT; } - if (ev->metaKey) { m |= SAPP_MODIFIER_SUPER; } - m |= _sapp_emsc_mouse_button_mods(_sapp.emsc.mouse_buttons); - return m; -} - -#if defined(SOKOL_WGPU) -_SOKOL_PRIVATE void _sapp_emsc_wgpu_size_changed(void); -#endif - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenUiEvent* ui_event, void* user_data) { - _SOKOL_UNUSED(event_type); - _SOKOL_UNUSED(user_data); - double w, h; - emscripten_get_element_css_size(_sapp.html5_canvas_selector, &w, &h); - /* The above method might report zero when toggling HTML5 fullscreen, - in that case use the window's inner width reported by the - emscripten event. This works ok when toggling *into* fullscreen - but doesn't properly restore the previous canvas size when switching - back from fullscreen. - - In general, due to the HTML5's fullscreen API's flaky nature it is - recommended to use 'soft fullscreen' (stretching the WebGL canvas - over the browser windows client rect) with a CSS definition like this: - - position: absolute; - top: 0px; - left: 0px; - margin: 0px; - border: 0; - width: 100%; - height: 100%; - overflow: hidden; - display: block; - */ - if (w < 1.0) { - w = ui_event->windowInnerWidth; - } - else { - _sapp.window_width = (int)roundf(w); - } - if (h < 1.0) { - h = ui_event->windowInnerHeight; - } - else { - _sapp.window_height = (int)roundf(h); - } - if (_sapp.desc.high_dpi) { - _sapp.dpi_scale = emscripten_get_device_pixel_ratio(); - } - _sapp.framebuffer_width = (int)roundf(w * _sapp.dpi_scale); - _sapp.framebuffer_height = (int)roundf(h * _sapp.dpi_scale); - SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0)); - emscripten_set_canvas_element_size(_sapp.html5_canvas_selector, _sapp.framebuffer_width, _sapp.framebuffer_height); - #if defined(SOKOL_WGPU) - // on WebGPU: recreate size-dependent rendering surfaces - _sapp_emsc_wgpu_size_changed(); - #endif - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_RESIZED); - _sapp_call_event(&_sapp.event); - } - return true; -} - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_mouse_cb(int emsc_type, const EmscriptenMouseEvent* emsc_event, void* user_data) { - _SOKOL_UNUSED(user_data); - bool consume_event = !_sapp.desc.html5_bubble_mouse_events; - _sapp.emsc.mouse_buttons = emsc_event->buttons; - if (_sapp.mouse.locked) { - _sapp.mouse.dx = (float) emsc_event->movementX; - _sapp.mouse.dy = (float) emsc_event->movementY; - } else { - float new_x = emsc_event->targetX * _sapp.dpi_scale; - float new_y = emsc_event->targetY * _sapp.dpi_scale; - if (_sapp.mouse.pos_valid) { - _sapp.mouse.dx = new_x - _sapp.mouse.x; - _sapp.mouse.dy = new_y - _sapp.mouse.y; - } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; - } - if (_sapp_events_enabled() && (emsc_event->button >= 0) && (emsc_event->button < SAPP_MAX_MOUSEBUTTONS)) { - sapp_event_type type; - bool is_button_event = false; - bool clear_dxdy = false; - switch (emsc_type) { - case EMSCRIPTEN_EVENT_MOUSEDOWN: - type = SAPP_EVENTTYPE_MOUSE_DOWN; - is_button_event = true; - break; - case EMSCRIPTEN_EVENT_MOUSEUP: - type = SAPP_EVENTTYPE_MOUSE_UP; - is_button_event = true; - break; - case EMSCRIPTEN_EVENT_MOUSEMOVE: - type = SAPP_EVENTTYPE_MOUSE_MOVE; - break; - case EMSCRIPTEN_EVENT_MOUSEENTER: - type = SAPP_EVENTTYPE_MOUSE_ENTER; - clear_dxdy = true; - break; - case EMSCRIPTEN_EVENT_MOUSELEAVE: - type = SAPP_EVENTTYPE_MOUSE_LEAVE; - clear_dxdy = true; - break; - default: - type = SAPP_EVENTTYPE_INVALID; - break; - } - if (clear_dxdy) { - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - } - if (type != SAPP_EVENTTYPE_INVALID) { - _sapp_init_event(type); - _sapp.event.modifiers = _sapp_emsc_mouse_event_mods(emsc_event); - if (is_button_event) { - switch (emsc_event->button) { - case 0: _sapp.event.mouse_button = SAPP_MOUSEBUTTON_LEFT; break; - case 1: _sapp.event.mouse_button = SAPP_MOUSEBUTTON_MIDDLE; break; - case 2: _sapp.event.mouse_button = SAPP_MOUSEBUTTON_RIGHT; break; - default: _sapp.event.mouse_button = (sapp_mousebutton)emsc_event->button; break; - } - } else { - _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID; - } - consume_event |= _sapp_call_event(&_sapp.event); - } - // mouse lock can only be activated in mouse button events (not in move, enter or leave) - if (is_button_event) { - _sapp_emsc_update_mouse_lock_state(); - } - } - return consume_event; -} - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_wheel_cb(int emsc_type, const EmscriptenWheelEvent* emsc_event, void* user_data) { - _SOKOL_UNUSED(emsc_type); - _SOKOL_UNUSED(user_data); - bool consume_event = !_sapp.desc.html5_bubble_wheel_events; - _sapp.emsc.mouse_buttons = emsc_event->mouse.buttons; - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); - _sapp.event.modifiers = _sapp_emsc_mouse_event_mods(&emsc_event->mouse); - /* see https://github.com/floooh/sokol/issues/339 */ - float scale; - switch (emsc_event->deltaMode) { - case DOM_DELTA_PIXEL: scale = -0.04f; break; - case DOM_DELTA_LINE: scale = -1.33f; break; - case DOM_DELTA_PAGE: scale = -10.0f; break; // FIXME: this is a guess - default: scale = -0.1f; break; // shouldn't happen - } - _sapp.event.scroll_x = scale * (float)emsc_event->deltaX; - _sapp.event.scroll_y = scale * (float)emsc_event->deltaY; - consume_event |= _sapp_call_event(&_sapp.event); - } - _sapp_emsc_update_mouse_lock_state(); - return consume_event; -} - -static struct { - const char* str; - sapp_keycode code; -} _sapp_emsc_keymap[] = { - { "Backspace", SAPP_KEYCODE_BACKSPACE }, - { "Tab", SAPP_KEYCODE_TAB }, - { "Enter", SAPP_KEYCODE_ENTER }, - { "ShiftLeft", SAPP_KEYCODE_LEFT_SHIFT }, - { "ShiftRight", SAPP_KEYCODE_RIGHT_SHIFT }, - { "ControlLeft", SAPP_KEYCODE_LEFT_CONTROL }, - { "ControlRight", SAPP_KEYCODE_RIGHT_CONTROL }, - { "AltLeft", SAPP_KEYCODE_LEFT_ALT }, - { "AltRight", SAPP_KEYCODE_RIGHT_ALT }, - { "Pause", SAPP_KEYCODE_PAUSE }, - { "CapsLock", SAPP_KEYCODE_CAPS_LOCK }, - { "Escape", SAPP_KEYCODE_ESCAPE }, - { "Space", SAPP_KEYCODE_SPACE }, - { "PageUp", SAPP_KEYCODE_PAGE_UP }, - { "PageDown", SAPP_KEYCODE_PAGE_DOWN }, - { "End", SAPP_KEYCODE_END }, - { "Home", SAPP_KEYCODE_HOME }, - { "ArrowLeft", SAPP_KEYCODE_LEFT }, - { "ArrowUp", SAPP_KEYCODE_UP }, - { "ArrowRight", SAPP_KEYCODE_RIGHT }, - { "ArrowDown", SAPP_KEYCODE_DOWN }, - { "PrintScreen", SAPP_KEYCODE_PRINT_SCREEN }, - { "Insert", SAPP_KEYCODE_INSERT }, - { "Delete", SAPP_KEYCODE_DELETE }, - { "Digit0", SAPP_KEYCODE_0 }, - { "Digit1", SAPP_KEYCODE_1 }, - { "Digit2", SAPP_KEYCODE_2 }, - { "Digit3", SAPP_KEYCODE_3 }, - { "Digit4", SAPP_KEYCODE_4 }, - { "Digit5", SAPP_KEYCODE_5 }, - { "Digit6", SAPP_KEYCODE_6 }, - { "Digit7", SAPP_KEYCODE_7 }, - { "Digit8", SAPP_KEYCODE_8 }, - { "Digit9", SAPP_KEYCODE_9 }, - { "KeyA", SAPP_KEYCODE_A }, - { "KeyB", SAPP_KEYCODE_B }, - { "KeyC", SAPP_KEYCODE_C }, - { "KeyD", SAPP_KEYCODE_D }, - { "KeyE", SAPP_KEYCODE_E }, - { "KeyF", SAPP_KEYCODE_F }, - { "KeyG", SAPP_KEYCODE_G }, - { "KeyH", SAPP_KEYCODE_H }, - { "KeyI", SAPP_KEYCODE_I }, - { "KeyJ", SAPP_KEYCODE_J }, - { "KeyK", SAPP_KEYCODE_K }, - { "KeyL", SAPP_KEYCODE_L }, - { "KeyM", SAPP_KEYCODE_M }, - { "KeyN", SAPP_KEYCODE_N }, - { "KeyO", SAPP_KEYCODE_O }, - { "KeyP", SAPP_KEYCODE_P }, - { "KeyQ", SAPP_KEYCODE_Q }, - { "KeyR", SAPP_KEYCODE_R }, - { "KeyS", SAPP_KEYCODE_S }, - { "KeyT", SAPP_KEYCODE_T }, - { "KeyU", SAPP_KEYCODE_U }, - { "KeyV", SAPP_KEYCODE_V }, - { "KeyW", SAPP_KEYCODE_W }, - { "KeyX", SAPP_KEYCODE_X }, - { "KeyY", SAPP_KEYCODE_Y }, - { "KeyZ", SAPP_KEYCODE_Z }, - { "MetaLeft", SAPP_KEYCODE_LEFT_SUPER }, - { "MetaRight", SAPP_KEYCODE_RIGHT_SUPER }, - { "Numpad0", SAPP_KEYCODE_KP_0 }, - { "Numpad1", SAPP_KEYCODE_KP_1 }, - { "Numpad2", SAPP_KEYCODE_KP_2 }, - { "Numpad3", SAPP_KEYCODE_KP_3 }, - { "Numpad4", SAPP_KEYCODE_KP_4 }, - { "Numpad5", SAPP_KEYCODE_KP_5 }, - { "Numpad6", SAPP_KEYCODE_KP_6 }, - { "Numpad7", SAPP_KEYCODE_KP_7 }, - { "Numpad8", SAPP_KEYCODE_KP_8 }, - { "Numpad9", SAPP_KEYCODE_KP_9 }, - { "NumpadMultiply", SAPP_KEYCODE_KP_MULTIPLY }, - { "NumpadAdd", SAPP_KEYCODE_KP_ADD }, - { "NumpadSubtract", SAPP_KEYCODE_KP_SUBTRACT }, - { "NumpadDecimal", SAPP_KEYCODE_KP_DECIMAL }, - { "NumpadDivide", SAPP_KEYCODE_KP_DIVIDE }, - { "F1", SAPP_KEYCODE_F1 }, - { "F2", SAPP_KEYCODE_F2 }, - { "F3", SAPP_KEYCODE_F3 }, - { "F4", SAPP_KEYCODE_F4 }, - { "F5", SAPP_KEYCODE_F5 }, - { "F6", SAPP_KEYCODE_F6 }, - { "F7", SAPP_KEYCODE_F7 }, - { "F8", SAPP_KEYCODE_F8 }, - { "F9", SAPP_KEYCODE_F9 }, - { "F10", SAPP_KEYCODE_F10 }, - { "F11", SAPP_KEYCODE_F11 }, - { "F12", SAPP_KEYCODE_F12 }, - { "NumLock", SAPP_KEYCODE_NUM_LOCK }, - { "ScrollLock", SAPP_KEYCODE_SCROLL_LOCK }, - { "Semicolon", SAPP_KEYCODE_SEMICOLON }, - { "Equal", SAPP_KEYCODE_EQUAL }, - { "Comma", SAPP_KEYCODE_COMMA }, - { "Minus", SAPP_KEYCODE_MINUS }, - { "Period", SAPP_KEYCODE_PERIOD }, - { "Slash", SAPP_KEYCODE_SLASH }, - { "Backquote", SAPP_KEYCODE_GRAVE_ACCENT }, - { "BracketLeft", SAPP_KEYCODE_LEFT_BRACKET }, - { "Backslash", SAPP_KEYCODE_BACKSLASH }, - { "BracketRight", SAPP_KEYCODE_RIGHT_BRACKET }, - { "Quote", SAPP_KEYCODE_GRAVE_ACCENT }, // FIXME: ??? - { 0, SAPP_KEYCODE_INVALID }, -}; - -_SOKOL_PRIVATE sapp_keycode _sapp_emsc_translate_key(const char* str) { - int i = 0; - const char* keystr; - while (( keystr = _sapp_emsc_keymap[i].str )) { - if (0 == strcmp(str, keystr)) { - return _sapp_emsc_keymap[i].code; - } - i += 1; - } - return SAPP_KEYCODE_INVALID; -} - -// returns true if the key code is a 'character key', this is used to decide -// if a key event needs to bubble up to create a char event -_SOKOL_PRIVATE bool _sapp_emsc_is_char_key(sapp_keycode key_code) { - return key_code < SAPP_KEYCODE_WORLD_1; -} - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboardEvent* emsc_event, void* user_data) { - _SOKOL_UNUSED(user_data); - bool consume_event = false; - if (_sapp_events_enabled()) { - sapp_event_type type; - switch (emsc_type) { - case EMSCRIPTEN_EVENT_KEYDOWN: - type = SAPP_EVENTTYPE_KEY_DOWN; - break; - case EMSCRIPTEN_EVENT_KEYUP: - type = SAPP_EVENTTYPE_KEY_UP; - break; - case EMSCRIPTEN_EVENT_KEYPRESS: - type = SAPP_EVENTTYPE_CHAR; - break; - default: - type = SAPP_EVENTTYPE_INVALID; - break; - } - if (type != SAPP_EVENTTYPE_INVALID) { - bool send_keyup_followup = false; - _sapp_init_event(type); - _sapp.event.key_repeat = emsc_event->repeat; - _sapp.event.modifiers = _sapp_emsc_key_event_mods(emsc_event); - if (type == SAPP_EVENTTYPE_CHAR) { - // NOTE: charCode doesn't appear to be supported on Android Chrome - _sapp.event.char_code = emsc_event->charCode; - consume_event |= !_sapp.desc.html5_bubble_char_events; - } else { - if (0 != emsc_event->code[0]) { - // This code path is for desktop browsers which send untranslated 'physical' key code strings - // (which is what we actually want for key events) - _sapp.event.key_code = _sapp_emsc_translate_key(emsc_event->code); - } else { - // This code path is for mobile browsers which only send localized key code - // strings. Note that the translation will only work for a small subset - // of localization-agnostic keys (like Enter, arrow keys, etc...), but - // regular alpha-numeric keys will all result in an SAPP_KEYCODE_INVALID) - _sapp.event.key_code = _sapp_emsc_translate_key(emsc_event->key); - } - - // Special hack for macOS: if the Super key is pressed, macOS doesn't - // send keyUp events. As a workaround, to prevent keys from - // "sticking", we'll send a keyup event following a keydown - // when the SUPER key is pressed - if ((type == SAPP_EVENTTYPE_KEY_DOWN) && - (_sapp.event.key_code != SAPP_KEYCODE_LEFT_SUPER) && - (_sapp.event.key_code != SAPP_KEYCODE_RIGHT_SUPER) && - (_sapp.event.modifiers & SAPP_MODIFIER_SUPER)) - { - send_keyup_followup = true; - } - - // 'character key events' will always need to bubble up, otherwise the browser - // wouldn't be able to generate character events. - if (!_sapp_emsc_is_char_key(_sapp.event.key_code)) { - consume_event |= !_sapp.desc.html5_bubble_key_events; - } - } - consume_event |= _sapp_call_event(&_sapp.event); - if (send_keyup_followup) { - _sapp.event.type = SAPP_EVENTTYPE_KEY_UP; - consume_event |= _sapp_call_event(&_sapp.event); - } - } - } - _sapp_emsc_update_mouse_lock_state(); - return consume_event; -} - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_touch_cb(int emsc_type, const EmscriptenTouchEvent* emsc_event, void* user_data) { - _SOKOL_UNUSED(user_data); - bool consume_event = !_sapp.desc.html5_bubble_touch_events; - if (_sapp_events_enabled()) { - sapp_event_type type; - switch (emsc_type) { - case EMSCRIPTEN_EVENT_TOUCHSTART: - type = SAPP_EVENTTYPE_TOUCHES_BEGAN; - break; - case EMSCRIPTEN_EVENT_TOUCHMOVE: - type = SAPP_EVENTTYPE_TOUCHES_MOVED; - break; - case EMSCRIPTEN_EVENT_TOUCHEND: - type = SAPP_EVENTTYPE_TOUCHES_ENDED; - break; - case EMSCRIPTEN_EVENT_TOUCHCANCEL: - type = SAPP_EVENTTYPE_TOUCHES_CANCELLED; - break; - default: - type = SAPP_EVENTTYPE_INVALID; - break; - } - if (type != SAPP_EVENTTYPE_INVALID) { - _sapp_init_event(type); - _sapp.event.modifiers = _sapp_emsc_touch_event_mods(emsc_event); - _sapp.event.num_touches = emsc_event->numTouches; - if (_sapp.event.num_touches > SAPP_MAX_TOUCHPOINTS) { - _sapp.event.num_touches = SAPP_MAX_TOUCHPOINTS; - } - for (int i = 0; i < _sapp.event.num_touches; i++) { - const EmscriptenTouchPoint* src = &emsc_event->touches[i]; - sapp_touchpoint* dst = &_sapp.event.touches[i]; - dst->identifier = (uintptr_t)src->identifier; - dst->pos_x = src->targetX * _sapp.dpi_scale; - dst->pos_y = src->targetY * _sapp.dpi_scale; - dst->changed = src->isChanged; - } - consume_event |= _sapp_call_event(&_sapp.event); - } - } - return consume_event; -} - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_focus_cb(int emsc_type, const EmscriptenFocusEvent* emsc_event, void* user_data) { - _SOKOL_UNUSED(emsc_type); - _SOKOL_UNUSED(emsc_event); - _SOKOL_UNUSED(user_data); - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_FOCUSED); - _sapp_call_event(&_sapp.event); - } - return true; -} - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_blur_cb(int emsc_type, const EmscriptenFocusEvent* emsc_event, void* user_data) { - _SOKOL_UNUSED(emsc_type); - _SOKOL_UNUSED(emsc_event); - _SOKOL_UNUSED(user_data); - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_UNFOCUSED); - _sapp_call_event(&_sapp.event); - } - return true; -} - -#if defined(SOKOL_GLES3) -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_webgl_context_cb(int emsc_type, const void* reserved, void* user_data) { - _SOKOL_UNUSED(reserved); - _SOKOL_UNUSED(user_data); - sapp_event_type type; - switch (emsc_type) { - case EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST: type = SAPP_EVENTTYPE_SUSPENDED; break; - case EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED: type = SAPP_EVENTTYPE_RESUMED; break; - default: type = SAPP_EVENTTYPE_INVALID; break; - } - if (_sapp_events_enabled() && (SAPP_EVENTTYPE_INVALID != type)) { - _sapp_init_event(type); - _sapp_call_event(&_sapp.event); - } - return true; -} - -_SOKOL_PRIVATE void _sapp_emsc_webgl_init(void) { - EmscriptenWebGLContextAttributes attrs; - emscripten_webgl_init_context_attributes(&attrs); - attrs.alpha = _sapp.desc.alpha; - attrs.depth = true; - attrs.stencil = true; - attrs.antialias = _sapp.sample_count > 1; - attrs.premultipliedAlpha = _sapp.desc.html5_premultiplied_alpha; - attrs.preserveDrawingBuffer = _sapp.desc.html5_preserve_drawing_buffer; - attrs.enableExtensionsByDefault = true; - attrs.majorVersion = 2; - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(_sapp.html5_canvas_selector, &attrs); - // FIXME: error message? - emscripten_webgl_make_context_current(ctx); - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); - - // FIXME: remove PVRTC support here and in sokol-gfx at some point - // some WebGL extension are not enabled automatically by emscripten - emscripten_webgl_enable_extension(ctx, "WEBKIT_WEBGL_compressed_texture_pvrtc"); -} -#endif - -#if defined(SOKOL_WGPU) - -_SOKOL_PRIVATE void _sapp_emsc_wgpu_create_swapchain(void) { - SOKOL_ASSERT(_sapp.wgpu.instance); - SOKOL_ASSERT(_sapp.wgpu.device); - SOKOL_ASSERT(0 == _sapp.wgpu.surface); - SOKOL_ASSERT(0 == _sapp.wgpu.swapchain); - SOKOL_ASSERT(0 == _sapp.wgpu.msaa_tex); - SOKOL_ASSERT(0 == _sapp.wgpu.msaa_view); - SOKOL_ASSERT(0 == _sapp.wgpu.depth_stencil_tex); - SOKOL_ASSERT(0 == _sapp.wgpu.depth_stencil_view); - SOKOL_ASSERT(0 == _sapp.wgpu.swapchain_view); - - WGPUSurfaceDescriptorFromCanvasHTMLSelector canvas_desc; - _sapp_clear(&canvas_desc, sizeof(canvas_desc)); - canvas_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; - canvas_desc.selector = _sapp.html5_canvas_selector; - WGPUSurfaceDescriptor surf_desc; - _sapp_clear(&surf_desc, sizeof(surf_desc)); - surf_desc.nextInChain = &canvas_desc.chain; - _sapp.wgpu.surface = wgpuInstanceCreateSurface(_sapp.wgpu.instance, &surf_desc); - if (0 == _sapp.wgpu.surface) { - _SAPP_PANIC(WGPU_SWAPCHAIN_CREATE_SURFACE_FAILED); - } - _sapp.wgpu.render_format = wgpuSurfaceGetPreferredFormat(_sapp.wgpu.surface, _sapp.wgpu.adapter); - - WGPUSwapChainDescriptor sc_desc; - _sapp_clear(&sc_desc, sizeof(sc_desc)); - sc_desc.usage = WGPUTextureUsage_RenderAttachment; - sc_desc.format = _sapp.wgpu.render_format; - sc_desc.width = (uint32_t)_sapp.framebuffer_width; - sc_desc.height = (uint32_t)_sapp.framebuffer_height; - sc_desc.presentMode = WGPUPresentMode_Fifo; - _sapp.wgpu.swapchain = wgpuDeviceCreateSwapChain(_sapp.wgpu.device, _sapp.wgpu.surface, &sc_desc); - if (0 == _sapp.wgpu.swapchain) { - _SAPP_PANIC(WGPU_SWAPCHAIN_CREATE_SWAPCHAIN_FAILED); - } - - WGPUTextureDescriptor ds_desc; - _sapp_clear(&ds_desc, sizeof(ds_desc)); - ds_desc.usage = WGPUTextureUsage_RenderAttachment; - ds_desc.dimension = WGPUTextureDimension_2D; - ds_desc.size.width = (uint32_t)_sapp.framebuffer_width; - ds_desc.size.height = (uint32_t)_sapp.framebuffer_height; - ds_desc.size.depthOrArrayLayers = 1; - ds_desc.format = WGPUTextureFormat_Depth32FloatStencil8; - ds_desc.mipLevelCount = 1; - ds_desc.sampleCount = (uint32_t)_sapp.sample_count; - _sapp.wgpu.depth_stencil_tex = wgpuDeviceCreateTexture(_sapp.wgpu.device, &ds_desc); - if (0 == _sapp.wgpu.depth_stencil_tex) { - _SAPP_PANIC(WGPU_SWAPCHAIN_CREATE_DEPTH_STENCIL_TEXTURE_FAILED); - } - _sapp.wgpu.depth_stencil_view = wgpuTextureCreateView(_sapp.wgpu.depth_stencil_tex, 0); - if (0 == _sapp.wgpu.depth_stencil_view) { - _SAPP_PANIC(WGPU_SWAPCHAIN_CREATE_DEPTH_STENCIL_VIEW_FAILED); - } - - if (_sapp.sample_count > 1) { - WGPUTextureDescriptor msaa_desc; - _sapp_clear(&msaa_desc, sizeof(msaa_desc)); - msaa_desc.usage = WGPUTextureUsage_RenderAttachment; - msaa_desc.dimension = WGPUTextureDimension_2D; - msaa_desc.size.width = (uint32_t)_sapp.framebuffer_width; - msaa_desc.size.height = (uint32_t)_sapp.framebuffer_height; - msaa_desc.size.depthOrArrayLayers = 1; - msaa_desc.format = _sapp.wgpu.render_format; - msaa_desc.mipLevelCount = 1; - msaa_desc.sampleCount = (uint32_t)_sapp.sample_count; - _sapp.wgpu.msaa_tex = wgpuDeviceCreateTexture(_sapp.wgpu.device, &msaa_desc); - if (0 == _sapp.wgpu.msaa_tex) { - _SAPP_PANIC(WGPU_SWAPCHAIN_CREATE_MSAA_TEXTURE_FAILED); - } - _sapp.wgpu.msaa_view = wgpuTextureCreateView(_sapp.wgpu.msaa_tex, 0); - if (0 == _sapp.wgpu.msaa_view) { - _SAPP_PANIC(WGPU_SWAPCHAIN_CREATE_MSAA_VIEW_FAILED); - } - } -} - -_SOKOL_PRIVATE void _sapp_emsc_wgpu_discard_swapchain(void) { - if (_sapp.wgpu.msaa_view) { - wgpuTextureViewRelease(_sapp.wgpu.msaa_view); - _sapp.wgpu.msaa_view = 0; - } - if (_sapp.wgpu.msaa_tex) { - wgpuTextureRelease(_sapp.wgpu.msaa_tex); - _sapp.wgpu.msaa_tex = 0; - } - if (_sapp.wgpu.depth_stencil_view) { - wgpuTextureViewRelease(_sapp.wgpu.depth_stencil_view); - _sapp.wgpu.depth_stencil_view = 0; - } - if (_sapp.wgpu.depth_stencil_tex) { - wgpuTextureRelease(_sapp.wgpu.depth_stencil_tex); - _sapp.wgpu.depth_stencil_tex = 0; - } - if (_sapp.wgpu.swapchain) { - wgpuSwapChainRelease(_sapp.wgpu.swapchain); - _sapp.wgpu.swapchain = 0; - } - if (_sapp.wgpu.surface) { - wgpuSurfaceRelease(_sapp.wgpu.surface); - _sapp.wgpu.surface = 0; - } -} - -_SOKOL_PRIVATE void _sapp_emsc_wgpu_size_changed(void) { - _sapp_emsc_wgpu_discard_swapchain(); - _sapp_emsc_wgpu_create_swapchain(); -} - -_SOKOL_PRIVATE void _sapp_emsc_wgpu_request_device_cb(WGPURequestDeviceStatus status, WGPUDevice device, const char* msg, void* userdata) { - _SOKOL_UNUSED(msg); - _SOKOL_UNUSED(userdata); - SOKOL_ASSERT(!_sapp.wgpu.async_init_done); - if (status != WGPURequestDeviceStatus_Success) { - if (status == WGPURequestDeviceStatus_Error) { - _SAPP_PANIC(WGPU_REQUEST_DEVICE_STATUS_ERROR); - } else { - _SAPP_PANIC(WGPU_REQUEST_DEVICE_STATUS_UNKNOWN); - } - } - SOKOL_ASSERT(device); - _sapp.wgpu.device = device; - _sapp_emsc_wgpu_create_swapchain(); - _sapp.wgpu.async_init_done = true; -} - -_SOKOL_PRIVATE void _sapp_emsc_wgpu_request_adapter_cb(WGPURequestAdapterStatus status, WGPUAdapter adapter, const char* msg, void* userdata) { - _SOKOL_UNUSED(msg); - _SOKOL_UNUSED(userdata); - if (status != WGPURequestAdapterStatus_Success) { - switch (status) { - case WGPURequestAdapterStatus_Unavailable: _SAPP_PANIC(WGPU_REQUEST_ADAPTER_STATUS_UNAVAILABLE); break; - case WGPURequestAdapterStatus_Error: _SAPP_PANIC(WGPU_REQUEST_ADAPTER_STATUS_ERROR); break; - default: _SAPP_PANIC(WGPU_REQUEST_ADAPTER_STATUS_UNKNOWN); break; - } - } - SOKOL_ASSERT(adapter); - _sapp.wgpu.adapter = adapter; - size_t cur_feature_index = 1; - #define _SAPP_WGPU_MAX_REQUESTED_FEATURES (8) - WGPUFeatureName requiredFeatures[_SAPP_WGPU_MAX_REQUESTED_FEATURES] = { - WGPUFeatureName_Depth32FloatStencil8, - }; - // check for optional features we're interested in - if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionBC)) { - SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES); - requiredFeatures[cur_feature_index++] = WGPUFeatureName_TextureCompressionBC; - } - if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionETC2)) { - SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES); - requiredFeatures[cur_feature_index++] = WGPUFeatureName_TextureCompressionETC2; - } - if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionASTC)) { - SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES); - requiredFeatures[cur_feature_index++] = WGPUFeatureName_TextureCompressionASTC; - } - if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_Float32Filterable)) { - SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES); - requiredFeatures[cur_feature_index++] = WGPUFeatureName_Float32Filterable; - } - #undef _SAPP_WGPU_MAX_REQUESTED_FEATURES - - WGPUDeviceDescriptor dev_desc; - _sapp_clear(&dev_desc, sizeof(dev_desc)); - dev_desc.requiredFeatureCount = cur_feature_index; - dev_desc.requiredFeatures = requiredFeatures, - wgpuAdapterRequestDevice(adapter, &dev_desc, _sapp_emsc_wgpu_request_device_cb, 0); -} - -_SOKOL_PRIVATE void _sapp_emsc_wgpu_init(void) { - SOKOL_ASSERT(0 == _sapp.wgpu.instance); - SOKOL_ASSERT(!_sapp.wgpu.async_init_done); - _sapp.wgpu.instance = wgpuCreateInstance(0); - if (0 == _sapp.wgpu.instance) { - _SAPP_PANIC(WGPU_CREATE_INSTANCE_FAILED); - } - // FIXME: power preference? - wgpuInstanceRequestAdapter(_sapp.wgpu.instance, 0, _sapp_emsc_wgpu_request_adapter_cb, 0); -} - -_SOKOL_PRIVATE void _sapp_emsc_wgpu_frame(void) { - if (_sapp.wgpu.async_init_done) { - _sapp.wgpu.swapchain_view = wgpuSwapChainGetCurrentTextureView(_sapp.wgpu.swapchain); - _sapp_frame(); - wgpuTextureViewRelease(_sapp.wgpu.swapchain_view); - _sapp.wgpu.swapchain_view = 0; - } -} -#endif // SOKOL_WGPU - -_SOKOL_PRIVATE void _sapp_emsc_register_eventhandlers(void) { - // NOTE: HTML canvas doesn't receive input focus, this is why key event handlers are added - // to the window object (this could be worked around by adding a "tab index" to the - // canvas) - emscripten_set_mousedown_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_mouseup_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_mousemove_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_mouseenter_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_mouseleave_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_wheel_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_wheel_cb); - emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_key_cb); - emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_key_cb); - emscripten_set_keypress_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_key_cb); - emscripten_set_touchstart_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_touch_cb); - emscripten_set_touchmove_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_touch_cb); - emscripten_set_touchend_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_touch_cb); - emscripten_set_touchcancel_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_touch_cb); - emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, _sapp_emsc_pointerlockchange_cb); - emscripten_set_pointerlockerror_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, _sapp_emsc_pointerlockerror_cb); - emscripten_set_focus_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_focus_cb); - emscripten_set_blur_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_blur_cb); - sapp_js_add_beforeunload_listener(); - if (_sapp.clipboard.enabled) { - sapp_js_add_clipboard_listener(); - } - if (_sapp.drop.enabled) { - sapp_js_add_dragndrop_listeners(&_sapp.html5_canvas_selector[1]); - } - #if defined(SOKOL_GLES3) - emscripten_set_webglcontextlost_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_webgl_context_cb); - emscripten_set_webglcontextrestored_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_webgl_context_cb); - #endif -} - -_SOKOL_PRIVATE void _sapp_emsc_unregister_eventhandlers(void) { - emscripten_set_mousedown_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_mouseup_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_mousemove_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_mouseenter_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_mouseleave_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_wheel_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); - emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); - emscripten_set_keypress_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); - emscripten_set_touchstart_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_touchmove_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_touchend_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_touchcancel_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, 0); - emscripten_set_pointerlockerror_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, 0); - emscripten_set_focus_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); - emscripten_set_blur_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); - if (!_sapp.desc.html5_canvas_resize) { - emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); - } - sapp_js_remove_beforeunload_listener(); - if (_sapp.clipboard.enabled) { - sapp_js_remove_clipboard_listener(); - } - if (_sapp.drop.enabled) { - sapp_js_remove_dragndrop_listeners(&_sapp.html5_canvas_selector[1]); - } - #if defined(SOKOL_GLES3) - emscripten_set_webglcontextlost_callback(_sapp.html5_canvas_selector, 0, true, 0); - emscripten_set_webglcontextrestored_callback(_sapp.html5_canvas_selector, 0, true, 0); - #endif -} - -_SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame_animation_loop(double time, void* userData) { - _SOKOL_UNUSED(userData); - _sapp_timing_external(&_sapp.timing, time / 1000.0); - - #if defined(SOKOL_WGPU) - _sapp_emsc_wgpu_frame(); - #else - _sapp_frame(); - #endif - - // quit-handling - if (_sapp.quit_requested) { - _sapp_init_event(SAPP_EVENTTYPE_QUIT_REQUESTED); - _sapp_call_event(&_sapp.event); - if (_sapp.quit_requested) { - _sapp.quit_ordered = true; - } - } - if (_sapp.quit_ordered) { - _sapp_emsc_unregister_eventhandlers(); - _sapp_call_cleanup(); - _sapp_discard_state(); - return EM_FALSE; - } - return EM_TRUE; -} - -_SOKOL_PRIVATE void _sapp_emsc_frame_main_loop(void) { - const double time = emscripten_performance_now(); - if (!_sapp_emsc_frame_animation_loop(time, 0)) { - emscripten_cancel_main_loop(); - } -} - -_SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { - _sapp_init_state(desc); - sapp_js_init(&_sapp.html5_canvas_selector[1]); - double w, h; - if (_sapp.desc.html5_canvas_resize) { - w = (double) _sapp_def(_sapp.desc.width, _SAPP_FALLBACK_DEFAULT_WINDOW_WIDTH); - h = (double) _sapp_def(_sapp.desc.height, _SAPP_FALLBACK_DEFAULT_WINDOW_HEIGHT); - } - else { - emscripten_get_element_css_size(_sapp.html5_canvas_selector, &w, &h); - emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, false, _sapp_emsc_size_changed); - } - if (_sapp.desc.high_dpi) { - _sapp.dpi_scale = emscripten_get_device_pixel_ratio(); - } - _sapp.window_width = (int)roundf(w); - _sapp.window_height = (int)roundf(h); - _sapp.framebuffer_width = (int)roundf(w * _sapp.dpi_scale); - _sapp.framebuffer_height = (int)roundf(h * _sapp.dpi_scale); - emscripten_set_canvas_element_size(_sapp.html5_canvas_selector, _sapp.framebuffer_width, _sapp.framebuffer_height); - #if defined(SOKOL_GLES3) - _sapp_emsc_webgl_init(); - #elif defined(SOKOL_WGPU) - _sapp_emsc_wgpu_init(); - #endif - _sapp.valid = true; - _sapp_emsc_register_eventhandlers(); - sapp_set_icon(&desc->icon); - - // start the frame loop - if (_sapp.desc.html5_use_emsc_set_main_loop) { - emscripten_set_main_loop(_sapp_emsc_frame_main_loop, 0, _sapp.desc.html5_emsc_set_main_loop_simulate_infinite_loop); - } else { - emscripten_request_animation_frame_loop(_sapp_emsc_frame_animation_loop, 0); - } - // NOT A BUG: do not call _sapp_discard_state() here, instead this is - // called in _sapp_emsc_frame() when the application is ordered to quit -} - -#if !defined(SOKOL_NO_ENTRY) -int main(int argc, char* argv[]) { - sapp_desc desc = sokol_main(argc, argv); - _sapp_emsc_run(&desc); - return 0; -} -#endif /* SOKOL_NO_ENTRY */ -#endif /* _SAPP_EMSCRIPTEN */ - -// ██████ ██ ██ ██ ███████ ██ ██████ ███████ ██████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ███ ██ ███████ █████ ██ ██████ █████ ██████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ███████ ██ ██ ███████ ███████ ██ ███████ ██ ██ ███████ -// -// >>gl helpers -#if defined(SOKOL_GLCORE) -typedef struct { - int red_bits; - int green_bits; - int blue_bits; - int alpha_bits; - int depth_bits; - int stencil_bits; - int samples; - bool doublebuffer; - uintptr_t handle; -} _sapp_gl_fbconfig; - -_SOKOL_PRIVATE void _sapp_gl_init_fbconfig(_sapp_gl_fbconfig* fbconfig) { - _sapp_clear(fbconfig, sizeof(_sapp_gl_fbconfig)); - /* -1 means "don't care" */ - fbconfig->red_bits = -1; - fbconfig->green_bits = -1; - fbconfig->blue_bits = -1; - fbconfig->alpha_bits = -1; - fbconfig->depth_bits = -1; - fbconfig->stencil_bits = -1; - fbconfig->samples = -1; -} - -typedef struct { - int least_missing; - int least_color_diff; - int least_extra_diff; - bool best_match; -} _sapp_gl_fbselect; - -_SOKOL_PRIVATE void _sapp_gl_init_fbselect(_sapp_gl_fbselect* fbselect) { - _sapp_clear(fbselect, sizeof(_sapp_gl_fbselect)); - fbselect->least_missing = 1000000; - fbselect->least_color_diff = 10000000; - fbselect->least_extra_diff = 10000000; - fbselect->best_match = false; -} - -// NOTE: this is used only in the WGL code path -_SOKOL_PRIVATE bool _sapp_gl_select_fbconfig(_sapp_gl_fbselect* fbselect, const _sapp_gl_fbconfig* desired, const _sapp_gl_fbconfig* current) { - int missing = 0; - if (desired->doublebuffer != current->doublebuffer) { - return false; - } - - if ((desired->alpha_bits > 0) && (current->alpha_bits == 0)) { - missing++; - } - if ((desired->depth_bits > 0) && (current->depth_bits == 0)) { - missing++; - } - if ((desired->stencil_bits > 0) && (current->stencil_bits == 0)) { - missing++; - } - if ((desired->samples > 0) && (current->samples == 0)) { - /* Technically, several multisampling buffers could be - involved, but that's a lower level implementation detail and - not important to us here, so we count them as one - */ - missing++; - } - - /* These polynomials make many small channel size differences matter - less than one large channel size difference - Calculate color channel size difference value - */ - int color_diff = 0; - if (desired->red_bits != -1) { - color_diff += (desired->red_bits - current->red_bits) * (desired->red_bits - current->red_bits); - } - if (desired->green_bits != -1) { - color_diff += (desired->green_bits - current->green_bits) * (desired->green_bits - current->green_bits); - } - if (desired->blue_bits != -1) { - color_diff += (desired->blue_bits - current->blue_bits) * (desired->blue_bits - current->blue_bits); - } - - /* Calculate non-color channel size difference value */ - int extra_diff = 0; - if (desired->alpha_bits != -1) { - extra_diff += (desired->alpha_bits - current->alpha_bits) * (desired->alpha_bits - current->alpha_bits); - } - if (desired->depth_bits != -1) { - extra_diff += (desired->depth_bits - current->depth_bits) * (desired->depth_bits - current->depth_bits); - } - if (desired->stencil_bits != -1) { - extra_diff += (desired->stencil_bits - current->stencil_bits) * (desired->stencil_bits - current->stencil_bits); - } - if (desired->samples != -1) { - extra_diff += (desired->samples - current->samples) * (desired->samples - current->samples); - } - - /* Figure out if the current one is better than the best one found so far - Least number of missing buffers is the most important heuristic, - then color buffer size match and lastly size match for other buffers - */ - bool new_closest = false; - if (missing < fbselect->least_missing) { - new_closest = true; - } else if (missing == fbselect->least_missing) { - if ((color_diff < fbselect->least_color_diff) || - ((color_diff == fbselect->least_color_diff) && (extra_diff < fbselect->least_extra_diff))) - { - new_closest = true; - } - } - if (new_closest) { - fbselect->least_missing = missing; - fbselect->least_color_diff = color_diff; - fbselect->least_extra_diff = extra_diff; - fbselect->best_match = (missing | color_diff | extra_diff) == 0; - } - return new_closest; -} - -// NOTE: this is used only in the GLX code path -_SOKOL_PRIVATE const _sapp_gl_fbconfig* _sapp_gl_choose_fbconfig(const _sapp_gl_fbconfig* desired, const _sapp_gl_fbconfig* alternatives, int count) { - int missing, least_missing = 1000000; - int color_diff, least_color_diff = 10000000; - int extra_diff, least_extra_diff = 10000000; - const _sapp_gl_fbconfig* current; - const _sapp_gl_fbconfig* closest = 0; - for (int i = 0; i < count; i++) { - current = alternatives + i; - if (desired->doublebuffer != current->doublebuffer) { - continue; - } - missing = 0; - if (desired->alpha_bits > 0 && current->alpha_bits == 0) { - missing++; - } - if (desired->depth_bits > 0 && current->depth_bits == 0) { - missing++; - } - if (desired->stencil_bits > 0 && current->stencil_bits == 0) { - missing++; - } - if (desired->samples > 0 && current->samples == 0) { - /* Technically, several multisampling buffers could be - involved, but that's a lower level implementation detail and - not important to us here, so we count them as one - */ - missing++; - } - - /* These polynomials make many small channel size differences matter - less than one large channel size difference - Calculate color channel size difference value - */ - color_diff = 0; - if (desired->red_bits != -1) { - color_diff += (desired->red_bits - current->red_bits) * (desired->red_bits - current->red_bits); - } - if (desired->green_bits != -1) { - color_diff += (desired->green_bits - current->green_bits) * (desired->green_bits - current->green_bits); - } - if (desired->blue_bits != -1) { - color_diff += (desired->blue_bits - current->blue_bits) * (desired->blue_bits - current->blue_bits); - } - - /* Calculate non-color channel size difference value */ - extra_diff = 0; - if (desired->alpha_bits != -1) { - extra_diff += (desired->alpha_bits - current->alpha_bits) * (desired->alpha_bits - current->alpha_bits); - } - if (desired->depth_bits != -1) { - extra_diff += (desired->depth_bits - current->depth_bits) * (desired->depth_bits - current->depth_bits); - } - if (desired->stencil_bits != -1) { - extra_diff += (desired->stencil_bits - current->stencil_bits) * (desired->stencil_bits - current->stencil_bits); - } - if (desired->samples != -1) { - extra_diff += (desired->samples - current->samples) * (desired->samples - current->samples); - } - - /* Figure out if the current one is better than the best one found so far - Least number of missing buffers is the most important heuristic, - then color buffer size match and lastly size match for other buffers - */ - if (missing < least_missing) { - closest = current; - } - else if (missing == least_missing) { - if ((color_diff < least_color_diff) || - (color_diff == least_color_diff && extra_diff < least_extra_diff)) - { - closest = current; - } - } - if (current == closest) { - least_missing = missing; - least_color_diff = color_diff; - least_extra_diff = extra_diff; - } - } - return closest; -} -#endif - -// ██ ██ ██ ███ ██ ██████ ██████ ██ ██ ███████ -// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ █ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ █ ██ ███████ -// ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ -// ███ ███ ██ ██ ████ ██████ ██████ ███ ███ ███████ -// -// >>windows -#if defined(_SAPP_WIN32) -_SOKOL_PRIVATE bool _sapp_win32_utf8_to_wide(const char* src, wchar_t* dst, int dst_num_bytes) { - SOKOL_ASSERT(src && dst && (dst_num_bytes > 1)); - _sapp_clear(dst, (size_t)dst_num_bytes); - const int dst_chars = dst_num_bytes / (int)sizeof(wchar_t); - const int dst_needed = MultiByteToWideChar(CP_UTF8, 0, src, -1, 0, 0); - if ((dst_needed > 0) && (dst_needed < dst_chars)) { - MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, dst_chars); - return true; - } - else { - /* input string doesn't fit into destination buffer */ - return false; - } -} - -_SOKOL_PRIVATE void _sapp_win32_app_event(sapp_event_type type) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_win32_init_keytable(void) { - /* same as GLFW */ - _sapp.keycodes[0x00B] = SAPP_KEYCODE_0; - _sapp.keycodes[0x002] = SAPP_KEYCODE_1; - _sapp.keycodes[0x003] = SAPP_KEYCODE_2; - _sapp.keycodes[0x004] = SAPP_KEYCODE_3; - _sapp.keycodes[0x005] = SAPP_KEYCODE_4; - _sapp.keycodes[0x006] = SAPP_KEYCODE_5; - _sapp.keycodes[0x007] = SAPP_KEYCODE_6; - _sapp.keycodes[0x008] = SAPP_KEYCODE_7; - _sapp.keycodes[0x009] = SAPP_KEYCODE_8; - _sapp.keycodes[0x00A] = SAPP_KEYCODE_9; - _sapp.keycodes[0x01E] = SAPP_KEYCODE_A; - _sapp.keycodes[0x030] = SAPP_KEYCODE_B; - _sapp.keycodes[0x02E] = SAPP_KEYCODE_C; - _sapp.keycodes[0x020] = SAPP_KEYCODE_D; - _sapp.keycodes[0x012] = SAPP_KEYCODE_E; - _sapp.keycodes[0x021] = SAPP_KEYCODE_F; - _sapp.keycodes[0x022] = SAPP_KEYCODE_G; - _sapp.keycodes[0x023] = SAPP_KEYCODE_H; - _sapp.keycodes[0x017] = SAPP_KEYCODE_I; - _sapp.keycodes[0x024] = SAPP_KEYCODE_J; - _sapp.keycodes[0x025] = SAPP_KEYCODE_K; - _sapp.keycodes[0x026] = SAPP_KEYCODE_L; - _sapp.keycodes[0x032] = SAPP_KEYCODE_M; - _sapp.keycodes[0x031] = SAPP_KEYCODE_N; - _sapp.keycodes[0x018] = SAPP_KEYCODE_O; - _sapp.keycodes[0x019] = SAPP_KEYCODE_P; - _sapp.keycodes[0x010] = SAPP_KEYCODE_Q; - _sapp.keycodes[0x013] = SAPP_KEYCODE_R; - _sapp.keycodes[0x01F] = SAPP_KEYCODE_S; - _sapp.keycodes[0x014] = SAPP_KEYCODE_T; - _sapp.keycodes[0x016] = SAPP_KEYCODE_U; - _sapp.keycodes[0x02F] = SAPP_KEYCODE_V; - _sapp.keycodes[0x011] = SAPP_KEYCODE_W; - _sapp.keycodes[0x02D] = SAPP_KEYCODE_X; - _sapp.keycodes[0x015] = SAPP_KEYCODE_Y; - _sapp.keycodes[0x02C] = SAPP_KEYCODE_Z; - _sapp.keycodes[0x028] = SAPP_KEYCODE_APOSTROPHE; - _sapp.keycodes[0x02B] = SAPP_KEYCODE_BACKSLASH; - _sapp.keycodes[0x033] = SAPP_KEYCODE_COMMA; - _sapp.keycodes[0x00D] = SAPP_KEYCODE_EQUAL; - _sapp.keycodes[0x029] = SAPP_KEYCODE_GRAVE_ACCENT; - _sapp.keycodes[0x01A] = SAPP_KEYCODE_LEFT_BRACKET; - _sapp.keycodes[0x00C] = SAPP_KEYCODE_MINUS; - _sapp.keycodes[0x034] = SAPP_KEYCODE_PERIOD; - _sapp.keycodes[0x01B] = SAPP_KEYCODE_RIGHT_BRACKET; - _sapp.keycodes[0x027] = SAPP_KEYCODE_SEMICOLON; - _sapp.keycodes[0x035] = SAPP_KEYCODE_SLASH; - _sapp.keycodes[0x056] = SAPP_KEYCODE_WORLD_2; - _sapp.keycodes[0x00E] = SAPP_KEYCODE_BACKSPACE; - _sapp.keycodes[0x153] = SAPP_KEYCODE_DELETE; - _sapp.keycodes[0x14F] = SAPP_KEYCODE_END; - _sapp.keycodes[0x01C] = SAPP_KEYCODE_ENTER; - _sapp.keycodes[0x001] = SAPP_KEYCODE_ESCAPE; - _sapp.keycodes[0x147] = SAPP_KEYCODE_HOME; - _sapp.keycodes[0x152] = SAPP_KEYCODE_INSERT; - _sapp.keycodes[0x15D] = SAPP_KEYCODE_MENU; - _sapp.keycodes[0x151] = SAPP_KEYCODE_PAGE_DOWN; - _sapp.keycodes[0x149] = SAPP_KEYCODE_PAGE_UP; - _sapp.keycodes[0x045] = SAPP_KEYCODE_PAUSE; - _sapp.keycodes[0x146] = SAPP_KEYCODE_PAUSE; - _sapp.keycodes[0x039] = SAPP_KEYCODE_SPACE; - _sapp.keycodes[0x00F] = SAPP_KEYCODE_TAB; - _sapp.keycodes[0x03A] = SAPP_KEYCODE_CAPS_LOCK; - _sapp.keycodes[0x145] = SAPP_KEYCODE_NUM_LOCK; - _sapp.keycodes[0x046] = SAPP_KEYCODE_SCROLL_LOCK; - _sapp.keycodes[0x03B] = SAPP_KEYCODE_F1; - _sapp.keycodes[0x03C] = SAPP_KEYCODE_F2; - _sapp.keycodes[0x03D] = SAPP_KEYCODE_F3; - _sapp.keycodes[0x03E] = SAPP_KEYCODE_F4; - _sapp.keycodes[0x03F] = SAPP_KEYCODE_F5; - _sapp.keycodes[0x040] = SAPP_KEYCODE_F6; - _sapp.keycodes[0x041] = SAPP_KEYCODE_F7; - _sapp.keycodes[0x042] = SAPP_KEYCODE_F8; - _sapp.keycodes[0x043] = SAPP_KEYCODE_F9; - _sapp.keycodes[0x044] = SAPP_KEYCODE_F10; - _sapp.keycodes[0x057] = SAPP_KEYCODE_F11; - _sapp.keycodes[0x058] = SAPP_KEYCODE_F12; - _sapp.keycodes[0x064] = SAPP_KEYCODE_F13; - _sapp.keycodes[0x065] = SAPP_KEYCODE_F14; - _sapp.keycodes[0x066] = SAPP_KEYCODE_F15; - _sapp.keycodes[0x067] = SAPP_KEYCODE_F16; - _sapp.keycodes[0x068] = SAPP_KEYCODE_F17; - _sapp.keycodes[0x069] = SAPP_KEYCODE_F18; - _sapp.keycodes[0x06A] = SAPP_KEYCODE_F19; - _sapp.keycodes[0x06B] = SAPP_KEYCODE_F20; - _sapp.keycodes[0x06C] = SAPP_KEYCODE_F21; - _sapp.keycodes[0x06D] = SAPP_KEYCODE_F22; - _sapp.keycodes[0x06E] = SAPP_KEYCODE_F23; - _sapp.keycodes[0x076] = SAPP_KEYCODE_F24; - _sapp.keycodes[0x038] = SAPP_KEYCODE_LEFT_ALT; - _sapp.keycodes[0x01D] = SAPP_KEYCODE_LEFT_CONTROL; - _sapp.keycodes[0x02A] = SAPP_KEYCODE_LEFT_SHIFT; - _sapp.keycodes[0x15B] = SAPP_KEYCODE_LEFT_SUPER; - _sapp.keycodes[0x137] = SAPP_KEYCODE_PRINT_SCREEN; - _sapp.keycodes[0x138] = SAPP_KEYCODE_RIGHT_ALT; - _sapp.keycodes[0x11D] = SAPP_KEYCODE_RIGHT_CONTROL; - _sapp.keycodes[0x036] = SAPP_KEYCODE_RIGHT_SHIFT; - _sapp.keycodes[0x136] = SAPP_KEYCODE_RIGHT_SHIFT; - _sapp.keycodes[0x15C] = SAPP_KEYCODE_RIGHT_SUPER; - _sapp.keycodes[0x150] = SAPP_KEYCODE_DOWN; - _sapp.keycodes[0x14B] = SAPP_KEYCODE_LEFT; - _sapp.keycodes[0x14D] = SAPP_KEYCODE_RIGHT; - _sapp.keycodes[0x148] = SAPP_KEYCODE_UP; - _sapp.keycodes[0x052] = SAPP_KEYCODE_KP_0; - _sapp.keycodes[0x04F] = SAPP_KEYCODE_KP_1; - _sapp.keycodes[0x050] = SAPP_KEYCODE_KP_2; - _sapp.keycodes[0x051] = SAPP_KEYCODE_KP_3; - _sapp.keycodes[0x04B] = SAPP_KEYCODE_KP_4; - _sapp.keycodes[0x04C] = SAPP_KEYCODE_KP_5; - _sapp.keycodes[0x04D] = SAPP_KEYCODE_KP_6; - _sapp.keycodes[0x047] = SAPP_KEYCODE_KP_7; - _sapp.keycodes[0x048] = SAPP_KEYCODE_KP_8; - _sapp.keycodes[0x049] = SAPP_KEYCODE_KP_9; - _sapp.keycodes[0x04E] = SAPP_KEYCODE_KP_ADD; - _sapp.keycodes[0x053] = SAPP_KEYCODE_KP_DECIMAL; - _sapp.keycodes[0x135] = SAPP_KEYCODE_KP_DIVIDE; - _sapp.keycodes[0x11C] = SAPP_KEYCODE_KP_ENTER; - _sapp.keycodes[0x037] = SAPP_KEYCODE_KP_MULTIPLY; - _sapp.keycodes[0x04A] = SAPP_KEYCODE_KP_SUBTRACT; -} -#endif // _SAPP_WIN32 - -#if defined(_SAPP_WIN32) - -#if defined(SOKOL_D3D11) - -#if defined(__cplusplus) -#define _sapp_d3d11_Release(self) (self)->Release() -#define _sapp_win32_refiid(iid) iid -#else -#define _sapp_d3d11_Release(self) (self)->lpVtbl->Release(self) -#define _sapp_win32_refiid(iid) &iid -#endif - -#define _SAPP_SAFE_RELEASE(obj) if (obj) { _sapp_d3d11_Release(obj); obj=0; } - - -static const IID _sapp_IID_ID3D11Texture2D = { 0x6f15aaf2,0xd208,0x4e89, {0x9a,0xb4,0x48,0x95,0x35,0xd3,0x4f,0x9c} }; -static const IID _sapp_IID_IDXGIDevice1 = { 0x77db970f,0x6276,0x48ba, {0xba,0x28,0x07,0x01,0x43,0xb4,0x39,0x2c} }; -static const IID _sapp_IID_IDXGIFactory = { 0x7b7166ec,0x21c7,0x44ae, {0xb2,0x1a,0xc9,0xae,0x32,0x1a,0xe3,0x69} }; - -static inline HRESULT _sapp_dxgi_GetBuffer(IDXGISwapChain* self, UINT Buffer, REFIID riid, void** ppSurface) { - #if defined(__cplusplus) - return self->GetBuffer(Buffer, riid, ppSurface); - #else - return self->lpVtbl->GetBuffer(self, Buffer, riid, ppSurface); - #endif -} - -static inline HRESULT _sapp_d3d11_QueryInterface(ID3D11Device* self, REFIID riid, void** ppvObject) { - #if defined(__cplusplus) - return self->QueryInterface(riid, ppvObject); - #else - return self->lpVtbl->QueryInterface(self, riid, ppvObject); - #endif -} - -static inline HRESULT _sapp_d3d11_CreateRenderTargetView(ID3D11Device* self, ID3D11Resource *pResource, const D3D11_RENDER_TARGET_VIEW_DESC* pDesc, ID3D11RenderTargetView** ppRTView) { - #if defined(__cplusplus) - return self->CreateRenderTargetView(pResource, pDesc, ppRTView); - #else - return self->lpVtbl->CreateRenderTargetView(self, pResource, pDesc, ppRTView); - #endif -} - -static inline HRESULT _sapp_d3d11_CreateTexture2D(ID3D11Device* self, const D3D11_TEXTURE2D_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Texture2D** ppTexture2D) { - #if defined(__cplusplus) - return self->CreateTexture2D(pDesc, pInitialData, ppTexture2D); - #else - return self->lpVtbl->CreateTexture2D(self, pDesc, pInitialData, ppTexture2D); - #endif -} - -static inline HRESULT _sapp_d3d11_CreateDepthStencilView(ID3D11Device* self, ID3D11Resource* pResource, const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc, ID3D11DepthStencilView** ppDepthStencilView) { - #if defined(__cplusplus) - return self->CreateDepthStencilView(pResource, pDesc, ppDepthStencilView); - #else - return self->lpVtbl->CreateDepthStencilView(self, pResource, pDesc, ppDepthStencilView); - #endif -} - -static inline HRESULT _sapp_dxgi_ResizeBuffers(IDXGISwapChain* self, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) { - #if defined(__cplusplus) - return self->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); - #else - return self->lpVtbl->ResizeBuffers(self, BufferCount, Width, Height, NewFormat, SwapChainFlags); - #endif -} - -static inline HRESULT _sapp_dxgi_Present(IDXGISwapChain* self, UINT SyncInterval, UINT Flags) { - #if defined(__cplusplus) - return self->Present(SyncInterval, Flags); - #else - return self->lpVtbl->Present(self, SyncInterval, Flags); - #endif -} - -static inline HRESULT _sapp_dxgi_GetFrameStatistics(IDXGISwapChain* self, DXGI_FRAME_STATISTICS* pStats) { - #if defined(__cplusplus) - return self->GetFrameStatistics(pStats); - #else - return self->lpVtbl->GetFrameStatistics(self, pStats); - #endif -} - -static inline HRESULT _sapp_dxgi_SetMaximumFrameLatency(IDXGIDevice1* self, UINT MaxLatency) { - #if defined(__cplusplus) - return self->SetMaximumFrameLatency(MaxLatency); - #else - return self->lpVtbl->SetMaximumFrameLatency(self, MaxLatency); - #endif -} - -static inline HRESULT _sapp_dxgi_GetAdapter(IDXGIDevice1* self, IDXGIAdapter** pAdapter) { - #if defined(__cplusplus) - return self->GetAdapter(pAdapter); - #else - return self->lpVtbl->GetAdapter(self, pAdapter); - #endif -} - -static inline HRESULT _sapp_dxgi_GetParent(IDXGIObject* self, REFIID riid, void** ppParent) { - #if defined(__cplusplus) - return self->GetParent(riid, ppParent); - #else - return self->lpVtbl->GetParent(self, riid, ppParent); - #endif -} - -static inline HRESULT _sapp_dxgi_MakeWindowAssociation(IDXGIFactory* self, HWND WindowHandle, UINT Flags) { - #if defined(__cplusplus) - return self->MakeWindowAssociation(WindowHandle, Flags); - #else - return self->lpVtbl->MakeWindowAssociation(self, WindowHandle, Flags); - #endif -} - -_SOKOL_PRIVATE void _sapp_d3d11_create_device_and_swapchain(void) { - DXGI_SWAP_CHAIN_DESC* sc_desc = &_sapp.d3d11.swap_chain_desc; - sc_desc->BufferDesc.Width = (UINT)_sapp.framebuffer_width; - sc_desc->BufferDesc.Height = (UINT)_sapp.framebuffer_height; - sc_desc->BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - sc_desc->BufferDesc.RefreshRate.Numerator = 60; - sc_desc->BufferDesc.RefreshRate.Denominator = 1; - sc_desc->OutputWindow = _sapp.win32.hwnd; - sc_desc->Windowed = true; - if (_sapp.win32.is_win10_or_greater) { - sc_desc->BufferCount = 2; - sc_desc->SwapEffect = (DXGI_SWAP_EFFECT) _SAPP_DXGI_SWAP_EFFECT_FLIP_DISCARD; - _sapp.d3d11.use_dxgi_frame_stats = true; - } - else { - sc_desc->BufferCount = 1; - sc_desc->SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - _sapp.d3d11.use_dxgi_frame_stats = false; - } - sc_desc->SampleDesc.Count = 1; - sc_desc->SampleDesc.Quality = 0; - sc_desc->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - UINT create_flags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT; - #if defined(SOKOL_DEBUG) - create_flags |= D3D11_CREATE_DEVICE_DEBUG; - #endif - D3D_FEATURE_LEVEL feature_level; - HRESULT hr = D3D11CreateDeviceAndSwapChain( - NULL, /* pAdapter (use default) */ - D3D_DRIVER_TYPE_HARDWARE, /* DriverType */ - NULL, /* Software */ - create_flags, /* Flags */ - NULL, /* pFeatureLevels */ - 0, /* FeatureLevels */ - D3D11_SDK_VERSION, /* SDKVersion */ - sc_desc, /* pSwapChainDesc */ - &_sapp.d3d11.swap_chain, /* ppSwapChain */ - &_sapp.d3d11.device, /* ppDevice */ - &feature_level, /* pFeatureLevel */ - &_sapp.d3d11.device_context); /* ppImmediateContext */ - _SOKOL_UNUSED(hr); - #if defined(SOKOL_DEBUG) - if (!SUCCEEDED(hr)) { - // if initialization with D3D11_CREATE_DEVICE_DEBUG fails, this could be because the - // 'D3D11 debug layer' stopped working, indicated by the error message: - // === - // D3D11CreateDevice: Flags (0x2) were specified which require the D3D11 SDK Layers for Windows 10, but they are not present on the system. - // These flags must be removed, or the Windows 10 SDK must be installed. - // Flags include: D3D11_CREATE_DEVICE_DEBUG - // === - // - // ...just retry with the DEBUG flag switched off - _SAPP_ERROR(WIN32_D3D11_CREATE_DEVICE_AND_SWAPCHAIN_WITH_DEBUG_FAILED); - create_flags &= ~D3D11_CREATE_DEVICE_DEBUG; - hr = D3D11CreateDeviceAndSwapChain( - NULL, /* pAdapter (use default) */ - D3D_DRIVER_TYPE_HARDWARE, /* DriverType */ - NULL, /* Software */ - create_flags, /* Flags */ - NULL, /* pFeatureLevels */ - 0, /* FeatureLevels */ - D3D11_SDK_VERSION, /* SDKVersion */ - sc_desc, /* pSwapChainDesc */ - &_sapp.d3d11.swap_chain, /* ppSwapChain */ - &_sapp.d3d11.device, /* ppDevice */ - &feature_level, /* pFeatureLevel */ - &_sapp.d3d11.device_context); /* ppImmediateContext */ - } - #endif - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.swap_chain && _sapp.d3d11.device && _sapp.d3d11.device_context); - - // minimize frame latency, disable Alt-Enter - hr = _sapp_d3d11_QueryInterface(_sapp.d3d11.device, _sapp_win32_refiid(_sapp_IID_IDXGIDevice1), (void**)&_sapp.d3d11.dxgi_device); - if (SUCCEEDED(hr) && _sapp.d3d11.dxgi_device) { - _sapp_dxgi_SetMaximumFrameLatency(_sapp.d3d11.dxgi_device, 1); - IDXGIAdapter* dxgi_adapter = 0; - hr = _sapp_dxgi_GetAdapter(_sapp.d3d11.dxgi_device, &dxgi_adapter); - if (SUCCEEDED(hr) && dxgi_adapter) { - IDXGIFactory* dxgi_factory = 0; - hr = _sapp_dxgi_GetParent((IDXGIObject*)dxgi_adapter, _sapp_win32_refiid(_sapp_IID_IDXGIFactory), (void**)&dxgi_factory); - if (SUCCEEDED(hr)) { - _sapp_dxgi_MakeWindowAssociation(dxgi_factory, _sapp.win32.hwnd, DXGI_MWA_NO_ALT_ENTER|DXGI_MWA_NO_PRINT_SCREEN); - _SAPP_SAFE_RELEASE(dxgi_factory); - } - else { - _SAPP_ERROR(WIN32_D3D11_GET_IDXGIFACTORY_FAILED); - } - _SAPP_SAFE_RELEASE(dxgi_adapter); - } - else { - _SAPP_ERROR(WIN32_D3D11_GET_IDXGIADAPTER_FAILED); - } - } - else { - _SAPP_PANIC(WIN32_D3D11_QUERY_INTERFACE_IDXGIDEVICE1_FAILED); - } -} - -_SOKOL_PRIVATE void _sapp_d3d11_destroy_device_and_swapchain(void) { - _SAPP_SAFE_RELEASE(_sapp.d3d11.swap_chain); - _SAPP_SAFE_RELEASE(_sapp.d3d11.dxgi_device); - _SAPP_SAFE_RELEASE(_sapp.d3d11.device_context); - _SAPP_SAFE_RELEASE(_sapp.d3d11.device); -} - -_SOKOL_PRIVATE void _sapp_d3d11_create_default_render_target(void) { - SOKOL_ASSERT(0 == _sapp.d3d11.rt); - SOKOL_ASSERT(0 == _sapp.d3d11.rtv); - SOKOL_ASSERT(0 == _sapp.d3d11.msaa_rt); - SOKOL_ASSERT(0 == _sapp.d3d11.msaa_rtv); - SOKOL_ASSERT(0 == _sapp.d3d11.ds); - SOKOL_ASSERT(0 == _sapp.d3d11.dsv); - - HRESULT hr; - - /* view for the swapchain-created framebuffer */ - hr = _sapp_dxgi_GetBuffer(_sapp.d3d11.swap_chain, 0, _sapp_win32_refiid(_sapp_IID_ID3D11Texture2D), (void**)&_sapp.d3d11.rt); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.rt); - hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.rt, NULL, &_sapp.d3d11.rtv); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.rtv); - - /* common desc for MSAA and depth-stencil texture */ - D3D11_TEXTURE2D_DESC tex_desc; - _sapp_clear(&tex_desc, sizeof(tex_desc)); - tex_desc.Width = (UINT)_sapp.framebuffer_width; - tex_desc.Height = (UINT)_sapp.framebuffer_height; - tex_desc.MipLevels = 1; - tex_desc.ArraySize = 1; - tex_desc.Usage = D3D11_USAGE_DEFAULT; - tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET; - tex_desc.SampleDesc.Count = (UINT) _sapp.sample_count; - tex_desc.SampleDesc.Quality = (UINT) (_sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0); - - /* create MSAA texture and view if antialiasing requested */ - if (_sapp.sample_count > 1) { - tex_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &_sapp.d3d11.msaa_rt); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.msaa_rt); - hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.msaa_rt, NULL, &_sapp.d3d11.msaa_rtv); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.msaa_rtv); - } - - /* texture and view for the depth-stencil-surface */ - tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; - tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &_sapp.d3d11.ds); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.ds); - hr = _sapp_d3d11_CreateDepthStencilView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.ds, NULL, &_sapp.d3d11.dsv); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.dsv); -} - -_SOKOL_PRIVATE void _sapp_d3d11_destroy_default_render_target(void) { - _SAPP_SAFE_RELEASE(_sapp.d3d11.rt); - _SAPP_SAFE_RELEASE(_sapp.d3d11.rtv); - _SAPP_SAFE_RELEASE(_sapp.d3d11.msaa_rt); - _SAPP_SAFE_RELEASE(_sapp.d3d11.msaa_rtv); - _SAPP_SAFE_RELEASE(_sapp.d3d11.ds); - _SAPP_SAFE_RELEASE(_sapp.d3d11.dsv); -} - -_SOKOL_PRIVATE void _sapp_d3d11_resize_default_render_target(void) { - if (_sapp.d3d11.swap_chain) { - _sapp_d3d11_destroy_default_render_target(); - _sapp_dxgi_ResizeBuffers(_sapp.d3d11.swap_chain, _sapp.d3d11.swap_chain_desc.BufferCount, (UINT)_sapp.framebuffer_width, (UINT)_sapp.framebuffer_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0); - _sapp_d3d11_create_default_render_target(); - } -} - -_SOKOL_PRIVATE void _sapp_d3d11_present(bool do_not_wait) { - UINT flags = 0; - if (_sapp.win32.is_win10_or_greater && do_not_wait) { - /* this hack/workaround somewhat improves window-movement and -sizing - responsiveness when rendering is controlled via WM_TIMER during window - move and resize on NVIDIA cards on Win10 with recent drivers. - */ - flags = DXGI_PRESENT_DO_NOT_WAIT; - } - _sapp_dxgi_Present(_sapp.d3d11.swap_chain, (UINT)_sapp.swap_interval, flags); -} - -#endif /* SOKOL_D3D11 */ - -#if defined(SOKOL_GLCORE) -_SOKOL_PRIVATE void _sapp_wgl_init(void) { - _sapp.wgl.opengl32 = LoadLibraryA("opengl32.dll"); - if (!_sapp.wgl.opengl32) { - _SAPP_PANIC(WIN32_LOAD_OPENGL32_DLL_FAILED); - } - SOKOL_ASSERT(_sapp.wgl.opengl32); - _sapp.wgl.CreateContext = (PFN_wglCreateContext)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglCreateContext"); - SOKOL_ASSERT(_sapp.wgl.CreateContext); - _sapp.wgl.DeleteContext = (PFN_wglDeleteContext)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglDeleteContext"); - SOKOL_ASSERT(_sapp.wgl.DeleteContext); - _sapp.wgl.GetProcAddress = (PFN_wglGetProcAddress)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglGetProcAddress"); - SOKOL_ASSERT(_sapp.wgl.GetProcAddress); - _sapp.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglGetCurrentDC"); - SOKOL_ASSERT(_sapp.wgl.GetCurrentDC); - _sapp.wgl.MakeCurrent = (PFN_wglMakeCurrent)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglMakeCurrent"); - SOKOL_ASSERT(_sapp.wgl.MakeCurrent); - _sapp.wgl.GetIntegerv = (void(WINAPI*)(uint32_t, int32_t*)) GetProcAddress(_sapp.wgl.opengl32, "glGetIntegerv"); - SOKOL_ASSERT(_sapp.wgl.GetIntegerv); - - _sapp.wgl.msg_hwnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, - L"SOKOLAPP", - L"sokol-app message window", - WS_CLIPSIBLINGS|WS_CLIPCHILDREN, - 0, 0, 1, 1, - NULL, NULL, - GetModuleHandleW(NULL), - NULL); - if (!_sapp.wgl.msg_hwnd) { - _SAPP_PANIC(WIN32_CREATE_HELPER_WINDOW_FAILED); - } - SOKOL_ASSERT(_sapp.wgl.msg_hwnd); - ShowWindow(_sapp.wgl.msg_hwnd, SW_HIDE); - MSG msg; - while (PeekMessageW(&msg, _sapp.wgl.msg_hwnd, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - _sapp.wgl.msg_dc = GetDC(_sapp.wgl.msg_hwnd); - if (!_sapp.wgl.msg_dc) { - _SAPP_PANIC(WIN32_HELPER_WINDOW_GETDC_FAILED); - } -} - -_SOKOL_PRIVATE void _sapp_wgl_shutdown(void) { - SOKOL_ASSERT(_sapp.wgl.opengl32 && _sapp.wgl.msg_hwnd); - DestroyWindow(_sapp.wgl.msg_hwnd); _sapp.wgl.msg_hwnd = 0; - FreeLibrary(_sapp.wgl.opengl32); _sapp.wgl.opengl32 = 0; -} - -_SOKOL_PRIVATE bool _sapp_wgl_has_ext(const char* ext, const char* extensions) { - SOKOL_ASSERT(ext && extensions); - const char* start = extensions; - while (true) { - const char* where = strstr(start, ext); - if (!where) { - return false; - } - const char* terminator = where + strlen(ext); - if ((where == start) || (*(where - 1) == ' ')) { - if (*terminator == ' ' || *terminator == '\0') { - break; - } - } - start = terminator; - } - return true; -} - -_SOKOL_PRIVATE bool _sapp_wgl_ext_supported(const char* ext) { - SOKOL_ASSERT(ext); - if (_sapp.wgl.GetExtensionsStringEXT) { - const char* extensions = _sapp.wgl.GetExtensionsStringEXT(); - if (extensions) { - if (_sapp_wgl_has_ext(ext, extensions)) { - return true; - } - } - } - if (_sapp.wgl.GetExtensionsStringARB) { - const char* extensions = _sapp.wgl.GetExtensionsStringARB(_sapp.wgl.GetCurrentDC()); - if (extensions) { - if (_sapp_wgl_has_ext(ext, extensions)) { - return true; - } - } - } - return false; -} - -_SOKOL_PRIVATE void _sapp_wgl_load_extensions(void) { - SOKOL_ASSERT(_sapp.wgl.msg_dc); - PIXELFORMATDESCRIPTOR pfd; - _sapp_clear(&pfd, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - if (!SetPixelFormat(_sapp.wgl.msg_dc, ChoosePixelFormat(_sapp.wgl.msg_dc, &pfd), &pfd)) { - _SAPP_PANIC(WIN32_DUMMY_CONTEXT_SET_PIXELFORMAT_FAILED); - } - HGLRC rc = _sapp.wgl.CreateContext(_sapp.wgl.msg_dc); - if (!rc) { - _SAPP_PANIC(WIN32_CREATE_DUMMY_CONTEXT_FAILED); - } - if (!_sapp.wgl.MakeCurrent(_sapp.wgl.msg_dc, rc)) { - _SAPP_PANIC(WIN32_DUMMY_CONTEXT_MAKE_CURRENT_FAILED); - } - _sapp.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void*) _sapp.wgl.GetProcAddress("wglGetExtensionsStringEXT"); - _sapp.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)(void*) _sapp.wgl.GetProcAddress("wglGetExtensionsStringARB"); - _sapp.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)(void*) _sapp.wgl.GetProcAddress("wglCreateContextAttribsARB"); - _sapp.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(void*) _sapp.wgl.GetProcAddress("wglSwapIntervalEXT"); - _sapp.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(void*) _sapp.wgl.GetProcAddress("wglGetPixelFormatAttribivARB"); - _sapp.wgl.arb_multisample = _sapp_wgl_ext_supported("WGL_ARB_multisample"); - _sapp.wgl.arb_create_context = _sapp_wgl_ext_supported("WGL_ARB_create_context"); - _sapp.wgl.arb_create_context_profile = _sapp_wgl_ext_supported("WGL_ARB_create_context_profile"); - _sapp.wgl.ext_swap_control = _sapp_wgl_ext_supported("WGL_EXT_swap_control"); - _sapp.wgl.arb_pixel_format = _sapp_wgl_ext_supported("WGL_ARB_pixel_format"); - _sapp.wgl.MakeCurrent(_sapp.wgl.msg_dc, 0); - _sapp.wgl.DeleteContext(rc); -} - -_SOKOL_PRIVATE int _sapp_wgl_attrib(int pixel_format, int attrib) { - SOKOL_ASSERT(_sapp.wgl.arb_pixel_format); - int value = 0; - if (!_sapp.wgl.GetPixelFormatAttribivARB(_sapp.win32.dc, pixel_format, 0, 1, &attrib, &value)) { - _SAPP_PANIC(WIN32_GET_PIXELFORMAT_ATTRIB_FAILED); - } - return value; -} - -_SOKOL_PRIVATE void _sapp_wgl_attribiv(int pixel_format, int num_attribs, const int* attribs, int* results) { - SOKOL_ASSERT(_sapp.wgl.arb_pixel_format); - if (!_sapp.wgl.GetPixelFormatAttribivARB(_sapp.win32.dc, pixel_format, 0, num_attribs, attribs, results)) { - _SAPP_PANIC(WIN32_GET_PIXELFORMAT_ATTRIB_FAILED); - } -} - -_SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) { - SOKOL_ASSERT(_sapp.win32.dc); - SOKOL_ASSERT(_sapp.wgl.arb_pixel_format); - - #define _sapp_wgl_num_query_tags (12) - const int query_tags[_sapp_wgl_num_query_tags] = { - WGL_SUPPORT_OPENGL_ARB, - WGL_DRAW_TO_WINDOW_ARB, - WGL_PIXEL_TYPE_ARB, - WGL_ACCELERATION_ARB, - WGL_DOUBLE_BUFFER_ARB, - WGL_RED_BITS_ARB, - WGL_GREEN_BITS_ARB, - WGL_BLUE_BITS_ARB, - WGL_ALPHA_BITS_ARB, - WGL_DEPTH_BITS_ARB, - WGL_STENCIL_BITS_ARB, - WGL_SAMPLES_ARB, - }; - const int result_support_opengl_index = 0; - const int result_draw_to_window_index = 1; - const int result_pixel_type_index = 2; - const int result_acceleration_index = 3; - const int result_double_buffer_index = 4; - const int result_red_bits_index = 5; - const int result_green_bits_index = 6; - const int result_blue_bits_index = 7; - const int result_alpha_bits_index = 8; - const int result_depth_bits_index = 9; - const int result_stencil_bits_index = 10; - const int result_samples_index = 11; - - int query_results[_sapp_wgl_num_query_tags] = {0}; - // Drop the last item if multisample extension is not supported. - // If in future querying with multiple extensions, will have to shuffle index values to have active extensions on the end. - int query_count = _sapp_wgl_num_query_tags; - if (!_sapp.wgl.arb_multisample) { - query_count = _sapp_wgl_num_query_tags - 1; - } - - int native_count = _sapp_wgl_attrib(1, WGL_NUMBER_PIXEL_FORMATS_ARB); - - _sapp_gl_fbconfig desired; - _sapp_gl_init_fbconfig(&desired); - desired.red_bits = 8; - desired.green_bits = 8; - desired.blue_bits = 8; - desired.alpha_bits = 8; - desired.depth_bits = 24; - desired.stencil_bits = 8; - desired.doublebuffer = true; - desired.samples = (_sapp.sample_count > 1) ? _sapp.sample_count : 0; - - int pixel_format = 0; - - _sapp_gl_fbselect fbselect; - _sapp_gl_init_fbselect(&fbselect); - for (int i = 0; i < native_count; i++) { - const int n = i + 1; - _sapp_wgl_attribiv(n, query_count, query_tags, query_results); - - if (query_results[result_support_opengl_index] == 0 - || query_results[result_draw_to_window_index] == 0 - || query_results[result_pixel_type_index] != WGL_TYPE_RGBA_ARB - || query_results[result_acceleration_index] == WGL_NO_ACCELERATION_ARB) - { - continue; - } - - _sapp_gl_fbconfig u; - _sapp_clear(&u, sizeof(u)); - u.red_bits = query_results[result_red_bits_index]; - u.green_bits = query_results[result_green_bits_index]; - u.blue_bits = query_results[result_blue_bits_index]; - u.alpha_bits = query_results[result_alpha_bits_index]; - u.depth_bits = query_results[result_depth_bits_index]; - u.stencil_bits = query_results[result_stencil_bits_index]; - u.doublebuffer = 0 != query_results[result_double_buffer_index]; - u.samples = query_results[result_samples_index]; // NOTE: If arb_multisample is not supported - just takes the default 0 - - // Test if this pixel format is better than the previous one - if (_sapp_gl_select_fbconfig(&fbselect, &desired, &u)) { - pixel_format = (uintptr_t)n; - - // Early exit if matching as good as possible - if (fbselect.best_match) { - break; - } - } - } - - return pixel_format; -} - -_SOKOL_PRIVATE void _sapp_wgl_create_context(void) { - int pixel_format = _sapp_wgl_find_pixel_format(); - if (0 == pixel_format) { - _SAPP_PANIC(WIN32_WGL_FIND_PIXELFORMAT_FAILED); - } - PIXELFORMATDESCRIPTOR pfd; - if (!DescribePixelFormat(_sapp.win32.dc, pixel_format, sizeof(pfd), &pfd)) { - _SAPP_PANIC(WIN32_WGL_DESCRIBE_PIXELFORMAT_FAILED); - } - if (!SetPixelFormat(_sapp.win32.dc, pixel_format, &pfd)) { - _SAPP_PANIC(WIN32_WGL_SET_PIXELFORMAT_FAILED); - } - if (!_sapp.wgl.arb_create_context) { - _SAPP_PANIC(WIN32_WGL_ARB_CREATE_CONTEXT_REQUIRED); - } - if (!_sapp.wgl.arb_create_context_profile) { - _SAPP_PANIC(WIN32_WGL_ARB_CREATE_CONTEXT_PROFILE_REQUIRED); - } - const int attrs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, _sapp.desc.gl_major_version, - WGL_CONTEXT_MINOR_VERSION_ARB, _sapp.desc.gl_minor_version, -#if defined(SOKOL_DEBUG) - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB, -#else - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, -#endif - WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - 0, 0 - }; - _sapp.wgl.gl_ctx = _sapp.wgl.CreateContextAttribsARB(_sapp.win32.dc, 0, attrs); - if (!_sapp.wgl.gl_ctx) { - const DWORD err = GetLastError(); - if (err == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) { - _SAPP_PANIC(WIN32_WGL_OPENGL_VERSION_NOT_SUPPORTED); - } - else if (err == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) { - _SAPP_PANIC(WIN32_WGL_OPENGL_PROFILE_NOT_SUPPORTED); - } - else if (err == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB)) { - _SAPP_PANIC(WIN32_WGL_INCOMPATIBLE_DEVICE_CONTEXT); - } - else { - _SAPP_PANIC(WIN32_WGL_CREATE_CONTEXT_ATTRIBS_FAILED_OTHER); - } - } - _sapp.wgl.MakeCurrent(_sapp.win32.dc, _sapp.wgl.gl_ctx); - if (_sapp.wgl.ext_swap_control) { - /* FIXME: DwmIsCompositionEnabled() (see GLFW) */ - _sapp.wgl.SwapIntervalEXT(_sapp.swap_interval); - } - const uint32_t gl_framebuffer_binding = 0x8CA6; - _sapp.wgl.GetIntegerv(gl_framebuffer_binding, (int32_t*)&_sapp.gl.framebuffer); -} - -_SOKOL_PRIVATE void _sapp_wgl_destroy_context(void) { - SOKOL_ASSERT(_sapp.wgl.gl_ctx); - _sapp.wgl.DeleteContext(_sapp.wgl.gl_ctx); - _sapp.wgl.gl_ctx = 0; -} - -_SOKOL_PRIVATE void _sapp_wgl_swap_buffers(void) { - SOKOL_ASSERT(_sapp.win32.dc); - /* FIXME: DwmIsCompositionEnabled? (see GLFW) */ - SwapBuffers(_sapp.win32.dc); -} -#endif /* SOKOL_GLCORE */ - -_SOKOL_PRIVATE bool _sapp_win32_wide_to_utf8(const wchar_t* src, char* dst, int dst_num_bytes) { - SOKOL_ASSERT(src && dst && (dst_num_bytes > 1)); - _sapp_clear(dst, (size_t)dst_num_bytes); - const int bytes_needed = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL); - if (bytes_needed <= dst_num_bytes) { - WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_num_bytes, NULL, NULL); - return true; - } - else { - return false; - } -} - -/* updates current window and framebuffer size from the window's client rect, returns true if size has changed */ -_SOKOL_PRIVATE bool _sapp_win32_update_dimensions(void) { - RECT rect; - if (GetClientRect(_sapp.win32.hwnd, &rect)) { - float window_width = (float)(rect.right - rect.left) / _sapp.win32.dpi.window_scale; - float window_height = (float)(rect.bottom - rect.top) / _sapp.win32.dpi.window_scale; - _sapp.window_width = (int)roundf(window_width); - _sapp.window_height = (int)roundf(window_height); - int fb_width = (int)roundf(window_width * _sapp.win32.dpi.content_scale); - int fb_height = (int)roundf(window_height * _sapp.win32.dpi.content_scale); - /* prevent a framebuffer size of 0 when window is minimized */ - if (0 == fb_width) { - fb_width = 1; - } - if (0 == fb_height) { - fb_height = 1; - } - if ((fb_width != _sapp.framebuffer_width) || (fb_height != _sapp.framebuffer_height)) { - _sapp.framebuffer_width = fb_width; - _sapp.framebuffer_height = fb_height; - return true; - } - } - else { - _sapp.window_width = _sapp.window_height = 1; - _sapp.framebuffer_width = _sapp.framebuffer_height = 1; - } - return false; -} - -_SOKOL_PRIVATE void _sapp_win32_set_fullscreen(bool fullscreen, UINT swp_flags) { - HMONITOR monitor = MonitorFromWindow(_sapp.win32.hwnd, MONITOR_DEFAULTTONEAREST); - MONITORINFO minfo; - _sapp_clear(&minfo, sizeof(minfo)); - minfo.cbSize = sizeof(MONITORINFO); - GetMonitorInfo(monitor, &minfo); - const RECT mr = minfo.rcMonitor; - const int monitor_w = mr.right - mr.left; - const int monitor_h = mr.bottom - mr.top; - - const DWORD win_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD win_style; - RECT rect = { 0, 0, 0, 0 }; - - _sapp.fullscreen = fullscreen; - if (!_sapp.fullscreen) { - win_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX; - rect = _sapp.win32.stored_window_rect; - } - else { - GetWindowRect(_sapp.win32.hwnd, &_sapp.win32.stored_window_rect); - win_style = WS_POPUP | WS_SYSMENU | WS_VISIBLE; - rect.left = mr.left; - rect.top = mr.top; - rect.right = rect.left + monitor_w; - rect.bottom = rect.top + monitor_h; - AdjustWindowRectEx(&rect, win_style, FALSE, win_ex_style); - } - const int win_w = rect.right - rect.left; - const int win_h = rect.bottom - rect.top; - const int win_x = rect.left; - const int win_y = rect.top; - SetWindowLongPtr(_sapp.win32.hwnd, GWL_STYLE, win_style); - SetWindowPos(_sapp.win32.hwnd, HWND_TOP, win_x, win_y, win_w, win_h, swp_flags | SWP_FRAMECHANGED); -} - -_SOKOL_PRIVATE void _sapp_win32_toggle_fullscreen(void) { - _sapp_win32_set_fullscreen(!_sapp.fullscreen, SWP_SHOWWINDOW); -} - -_SOKOL_PRIVATE void _sapp_win32_init_cursor(sapp_mouse_cursor cursor) { - SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM)); - // NOTE: the OCR_* constants are only defined if OEMRESOURCE is defined - // before windows.h is included, but we can't guarantee that because - // the sokol_app.h implementation may be included with other implementations - // in the same compilation unit - int id = 0; - switch (cursor) { - case SAPP_MOUSECURSOR_ARROW: id = 32512; break; // OCR_NORMAL - case SAPP_MOUSECURSOR_IBEAM: id = 32513; break; // OCR_IBEAM - case SAPP_MOUSECURSOR_CROSSHAIR: id = 32515; break; // OCR_CROSS - case SAPP_MOUSECURSOR_POINTING_HAND: id = 32649; break; // OCR_HAND - case SAPP_MOUSECURSOR_RESIZE_EW: id = 32644; break; // OCR_SIZEWE - case SAPP_MOUSECURSOR_RESIZE_NS: id = 32645; break; // OCR_SIZENS - case SAPP_MOUSECURSOR_RESIZE_NWSE: id = 32642; break; // OCR_SIZENWSE - case SAPP_MOUSECURSOR_RESIZE_NESW: id = 32643; break; // OCR_SIZENESW - case SAPP_MOUSECURSOR_RESIZE_ALL: id = 32646; break; // OCR_SIZEALL - case SAPP_MOUSECURSOR_NOT_ALLOWED: id = 32648; break; // OCR_NO - default: break; - } - if (id != 0) { - _sapp.win32.cursors[cursor] = (HCURSOR)LoadImageW(NULL, MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE|LR_SHARED); - } - // fallback: default cursor - if (0 == _sapp.win32.cursors[cursor]) { - // 32512 => IDC_ARROW - _sapp.win32.cursors[cursor] = LoadCursorW(NULL, MAKEINTRESOURCEW(32512)); - } - SOKOL_ASSERT(0 != _sapp.win32.cursors[cursor]); -} - -_SOKOL_PRIVATE void _sapp_win32_init_cursors(void) { - for (int i = 0; i < _SAPP_MOUSECURSOR_NUM; i++) { - _sapp_win32_init_cursor((sapp_mouse_cursor)i); - } -} - -_SOKOL_PRIVATE bool _sapp_win32_cursor_in_content_area(void) { - POINT pos; - if (!GetCursorPos(&pos)) { - return false; - } - if (WindowFromPoint(pos) != _sapp.win32.hwnd) { - return false; - } - RECT area; - GetClientRect(_sapp.win32.hwnd, &area); - ClientToScreen(_sapp.win32.hwnd, (POINT*)&area.left); - ClientToScreen(_sapp.win32.hwnd, (POINT*)&area.right); - return PtInRect(&area, pos) == TRUE; -} - -_SOKOL_PRIVATE void _sapp_win32_update_cursor(sapp_mouse_cursor cursor, bool shown, bool skip_area_test) { - // NOTE: when called from WM_SETCURSOR, the area test would be redundant - if (!skip_area_test) { - if (!_sapp_win32_cursor_in_content_area()) { - return; - } - } - if (!shown) { - SetCursor(NULL); - } - else { - SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM)); - SOKOL_ASSERT(0 != _sapp.win32.cursors[cursor]); - SetCursor(_sapp.win32.cursors[cursor]); - } -} - -_SOKOL_PRIVATE void _sapp_win32_capture_mouse(uint8_t btn_mask) { - if (0 == _sapp.win32.mouse_capture_mask) { - SetCapture(_sapp.win32.hwnd); - } - _sapp.win32.mouse_capture_mask |= btn_mask; -} - -_SOKOL_PRIVATE void _sapp_win32_release_mouse(uint8_t btn_mask) { - if (0 != _sapp.win32.mouse_capture_mask) { - _sapp.win32.mouse_capture_mask &= ~btn_mask; - if (0 == _sapp.win32.mouse_capture_mask) { - ReleaseCapture(); - } - } -} - -_SOKOL_PRIVATE void _sapp_win32_lock_mouse(bool lock) { - if (lock == _sapp.mouse.locked) { - return; - } - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - _sapp.mouse.locked = lock; - _sapp_win32_release_mouse(0xFF); - if (_sapp.mouse.locked) { - /* store the current mouse position, so it can be restored when unlocked */ - POINT pos; - BOOL res = GetCursorPos(&pos); - SOKOL_ASSERT(res); _SOKOL_UNUSED(res); - _sapp.win32.mouse_locked_x = pos.x; - _sapp.win32.mouse_locked_y = pos.y; - - /* while the mouse is locked, make the mouse cursor invisible and - confine the mouse movement to a small rectangle inside our window - (so that we don't miss any mouse up events) - */ - RECT client_rect = { - _sapp.win32.mouse_locked_x, - _sapp.win32.mouse_locked_y, - _sapp.win32.mouse_locked_x, - _sapp.win32.mouse_locked_y - }; - ClipCursor(&client_rect); - - /* make the mouse cursor invisible, this will stack with sapp_show_mouse() */ - ShowCursor(FALSE); - - /* enable raw input for mouse, starts sending WM_INPUT messages to WinProc (see GLFW) */ - const RAWINPUTDEVICE rid = { - 0x01, // usUsagePage: HID_USAGE_PAGE_GENERIC - 0x02, // usUsage: HID_USAGE_GENERIC_MOUSE - 0, // dwFlags - _sapp.win32.hwnd // hwndTarget - }; - if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { - _SAPP_ERROR(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_LOCK); - } - /* in case the raw mouse device only supports absolute position reporting, - we need to skip the dx/dy compution for the first WM_INPUT event - */ - _sapp.win32.raw_input_mousepos_valid = false; - } - else { - /* disable raw input for mouse */ - const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; - if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { - _SAPP_ERROR(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_UNLOCK); - } - - /* let the mouse roam freely again */ - ClipCursor(NULL); - ShowCursor(TRUE); - - /* restore the 'pre-locked' mouse position */ - BOOL res = SetCursorPos(_sapp.win32.mouse_locked_x, _sapp.win32.mouse_locked_y); - SOKOL_ASSERT(res); _SOKOL_UNUSED(res); - } -} - -_SOKOL_PRIVATE bool _sapp_win32_update_monitor(void) { - const HMONITOR cur_monitor = MonitorFromWindow(_sapp.win32.hwnd, MONITOR_DEFAULTTONULL); - if (cur_monitor != _sapp.win32.hmonitor) { - _sapp.win32.hmonitor = cur_monitor; - return true; - } - else { - return false; - } -} - -_SOKOL_PRIVATE uint32_t _sapp_win32_mods(void) { - uint32_t mods = 0; - if (GetKeyState(VK_SHIFT) & (1<<15)) { - mods |= SAPP_MODIFIER_SHIFT; - } - if (GetKeyState(VK_CONTROL) & (1<<15)) { - mods |= SAPP_MODIFIER_CTRL; - } - if (GetKeyState(VK_MENU) & (1<<15)) { - mods |= SAPP_MODIFIER_ALT; - } - if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1<<15)) { - mods |= SAPP_MODIFIER_SUPER; - } - const bool swapped = (TRUE == GetSystemMetrics(SM_SWAPBUTTON)); - if (GetAsyncKeyState(VK_LBUTTON)) { - mods |= swapped ? SAPP_MODIFIER_RMB : SAPP_MODIFIER_LMB; - } - if (GetAsyncKeyState(VK_RBUTTON)) { - mods |= swapped ? SAPP_MODIFIER_LMB : SAPP_MODIFIER_RMB; - } - if (GetAsyncKeyState(VK_MBUTTON)) { - mods |= SAPP_MODIFIER_MMB; - } - return mods; -} - -_SOKOL_PRIVATE void _sapp_win32_mouse_update(LPARAM lParam) { - if (!_sapp.mouse.locked) { - const float new_x = (float)GET_X_LPARAM(lParam) * _sapp.win32.dpi.mouse_scale; - const float new_y = (float)GET_Y_LPARAM(lParam) * _sapp.win32.dpi.mouse_scale; - if (_sapp.mouse.pos_valid) { - // don't update dx/dy in the very first event - _sapp.mouse.dx = new_x - _sapp.mouse.x; - _sapp.mouse.dy = new_y - _sapp.mouse.y; - } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; - } -} - -_SOKOL_PRIVATE void _sapp_win32_mouse_event(sapp_event_type type, sapp_mousebutton btn) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp.event.modifiers = _sapp_win32_mods(); - _sapp.event.mouse_button = btn; - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_win32_scroll_event(float x, float y) { - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); - _sapp.event.modifiers = _sapp_win32_mods(); - _sapp.event.scroll_x = -x / 30.0f; - _sapp.event.scroll_y = y / 30.0f; - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_win32_key_event(sapp_event_type type, int vk, bool repeat) { - if (_sapp_events_enabled() && (vk < SAPP_MAX_KEYCODES)) { - _sapp_init_event(type); - _sapp.event.modifiers = _sapp_win32_mods(); - _sapp.event.key_code = _sapp.keycodes[vk]; - _sapp.event.key_repeat = repeat; - _sapp_call_event(&_sapp.event); - /* check if a CLIPBOARD_PASTED event must be sent too */ - if (_sapp.clipboard.enabled && - (type == SAPP_EVENTTYPE_KEY_DOWN) && - (_sapp.event.modifiers == SAPP_MODIFIER_CTRL) && - (_sapp.event.key_code == SAPP_KEYCODE_V)) - { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); - _sapp_call_event(&_sapp.event); - } - } -} - -_SOKOL_PRIVATE void _sapp_win32_char_event(uint32_t c, bool repeat) { - if (_sapp_events_enabled() && (c >= 32)) { - _sapp_init_event(SAPP_EVENTTYPE_CHAR); - _sapp.event.modifiers = _sapp_win32_mods(); - _sapp.event.char_code = c; - _sapp.event.key_repeat = repeat; - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_win32_dpi_changed(HWND hWnd, LPRECT proposed_win_rect) { - /* called on WM_DPICHANGED, which will only be sent to the application - if sapp_desc.high_dpi is true and the Windows version is recent enough - to support DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 - */ - SOKOL_ASSERT(_sapp.desc.high_dpi); - HINSTANCE user32 = LoadLibraryA("user32.dll"); - if (!user32) { - return; - } - typedef UINT(WINAPI * GETDPIFORWINDOW_T)(HWND hwnd); - GETDPIFORWINDOW_T fn_getdpiforwindow = (GETDPIFORWINDOW_T)(void*)GetProcAddress(user32, "GetDpiForWindow"); - if (fn_getdpiforwindow) { - UINT dpix = fn_getdpiforwindow(_sapp.win32.hwnd); - // NOTE: for high-dpi apps, mouse_scale remains one - _sapp.win32.dpi.window_scale = (float)dpix / 96.0f; - _sapp.win32.dpi.content_scale = _sapp.win32.dpi.window_scale; - _sapp.dpi_scale = _sapp.win32.dpi.window_scale; - SetWindowPos(hWnd, 0, - proposed_win_rect->left, - proposed_win_rect->top, - proposed_win_rect->right - proposed_win_rect->left, - proposed_win_rect->bottom - proposed_win_rect->top, - SWP_NOZORDER | SWP_NOACTIVATE); - } - FreeLibrary(user32); -} - -_SOKOL_PRIVATE void _sapp_win32_files_dropped(HDROP hdrop) { - if (!_sapp.drop.enabled) { - return; - } - _sapp_clear_drop_buffer(); - bool drop_failed = false; - const int count = (int) DragQueryFileW(hdrop, 0xffffffff, NULL, 0); - _sapp.drop.num_files = (count > _sapp.drop.max_files) ? _sapp.drop.max_files : count; - for (UINT i = 0; i < (UINT)_sapp.drop.num_files; i++) { - const UINT num_chars = DragQueryFileW(hdrop, i, NULL, 0) + 1; - WCHAR* buffer = (WCHAR*) _sapp_malloc_clear(num_chars * sizeof(WCHAR)); - DragQueryFileW(hdrop, i, buffer, num_chars); - if (!_sapp_win32_wide_to_utf8(buffer, _sapp_dropped_file_path_ptr((int)i), _sapp.drop.max_path_length)) { - _SAPP_ERROR(DROPPED_FILE_PATH_TOO_LONG); - drop_failed = true; - } - _sapp_free(buffer); - } - DragFinish(hdrop); - if (!drop_failed) { - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); - _sapp.event.modifiers = _sapp_win32_mods(); - _sapp_call_event(&_sapp.event); - } - } - else { - _sapp_clear_drop_buffer(); - _sapp.drop.num_files = 0; - } -} - -_SOKOL_PRIVATE void _sapp_win32_timing_measure(void) { - #if defined(SOKOL_D3D11) - // on D3D11, use the more precise DXGI timestamp - if (_sapp.d3d11.use_dxgi_frame_stats) { - DXGI_FRAME_STATISTICS dxgi_stats; - _sapp_clear(&dxgi_stats, sizeof(dxgi_stats)); - HRESULT hr = _sapp_dxgi_GetFrameStatistics(_sapp.d3d11.swap_chain, &dxgi_stats); - if (SUCCEEDED(hr)) { - if (dxgi_stats.SyncRefreshCount != _sapp.d3d11.sync_refresh_count) { - if ((_sapp.d3d11.sync_refresh_count + 1) != dxgi_stats.SyncRefreshCount) { - _sapp_timing_discontinuity(&_sapp.timing); - } - _sapp.d3d11.sync_refresh_count = dxgi_stats.SyncRefreshCount; - LARGE_INTEGER qpc = dxgi_stats.SyncQPCTime; - const uint64_t now = (uint64_t)_sapp_int64_muldiv(qpc.QuadPart - _sapp.timing.timestamp.win.start.QuadPart, 1000000000, _sapp.timing.timestamp.win.freq.QuadPart); - _sapp_timing_external(&_sapp.timing, (double)now / 1000000000.0); - } - return; - } - } - // fallback if swap model isn't "flip-discard" or GetFrameStatistics failed for another reason - _sapp_timing_measure(&_sapp.timing); - #endif - #if defined(SOKOL_GLCORE) - _sapp_timing_measure(&_sapp.timing); - #endif - #if defined(SOKOL_NOAPI) - _sapp_timing_measure(&_sapp.timing); - #endif -} - -_SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - if (!_sapp.win32.in_create_window) { - switch (uMsg) { - case WM_CLOSE: - /* only give user a chance to intervene when sapp_quit() wasn't already called */ - if (!_sapp.quit_ordered) { - /* if window should be closed and event handling is enabled, give user code - a change to intervene via sapp_cancel_quit() - */ - _sapp.quit_requested = true; - _sapp_win32_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED); - /* if user code hasn't intervened, quit the app */ - if (_sapp.quit_requested) { - _sapp.quit_ordered = true; - } - } - if (_sapp.quit_ordered) { - PostQuitMessage(0); - } - return 0; - case WM_SYSCOMMAND: - switch (wParam & 0xFFF0) { - case SC_SCREENSAVE: - case SC_MONITORPOWER: - if (_sapp.fullscreen) { - /* disable screen saver and blanking in fullscreen mode */ - return 0; - } - break; - case SC_KEYMENU: - /* user trying to access menu via ALT */ - return 0; - } - break; - case WM_ERASEBKGND: - return 1; - case WM_SIZE: - { - const bool iconified = wParam == SIZE_MINIMIZED; - if (iconified != _sapp.win32.iconified) { - _sapp.win32.iconified = iconified; - if (iconified) { - _sapp_win32_app_event(SAPP_EVENTTYPE_ICONIFIED); - } - else { - _sapp_win32_app_event(SAPP_EVENTTYPE_RESTORED); - } - } - } - break; - case WM_SETFOCUS: - _sapp_win32_app_event(SAPP_EVENTTYPE_FOCUSED); - break; - case WM_KILLFOCUS: - /* if focus is lost for any reason, and we're in mouse locked mode, disable mouse lock */ - if (_sapp.mouse.locked) { - _sapp_win32_lock_mouse(false); - } - _sapp_win32_app_event(SAPP_EVENTTYPE_UNFOCUSED); - break; - case WM_SETCURSOR: - if (LOWORD(lParam) == HTCLIENT) { - _sapp_win32_update_cursor(_sapp.mouse.current_cursor, _sapp.mouse.shown, true); - return TRUE; - } - break; - case WM_DPICHANGED: - { - /* Update window's DPI and size if its moved to another monitor with a different DPI - Only sent if DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 is used. - */ - _sapp_win32_dpi_changed(hWnd, (LPRECT)lParam); - break; - } - case WM_LBUTTONDOWN: - _sapp_win32_mouse_update(lParam); - _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT); - _sapp_win32_capture_mouse(1<data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { - /* mouse only reports absolute position - NOTE: This code is untested and will most likely behave wrong in Remote Desktop sessions. - (such remote desktop sessions are setting the MOUSE_MOVE_ABSOLUTE flag). - See: https://github.com/floooh/sokol/issues/806 and - https://github.com/microsoft/DirectXTK/commit/ef56b63f3739381e451f7a5a5bd2c9779d2a7555) - */ - LONG new_x = raw_mouse_data->data.mouse.lLastX; - LONG new_y = raw_mouse_data->data.mouse.lLastY; - if (_sapp.win32.raw_input_mousepos_valid) { - _sapp.mouse.dx = (float) (new_x - _sapp.win32.raw_input_mousepos_x); - _sapp.mouse.dy = (float) (new_y - _sapp.win32.raw_input_mousepos_y); - } - _sapp.win32.raw_input_mousepos_x = new_x; - _sapp.win32.raw_input_mousepos_y = new_y; - _sapp.win32.raw_input_mousepos_valid = true; - } - else { - /* mouse reports movement delta (this seems to be the common case) */ - _sapp.mouse.dx = (float) raw_mouse_data->data.mouse.lLastX; - _sapp.mouse.dy = (float) raw_mouse_data->data.mouse.lLastY; - } - _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID); - } - break; - - case WM_MOUSELEAVE: - if (!_sapp.mouse.locked) { - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - _sapp.win32.mouse_tracked = false; - _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID); - } - break; - case WM_MOUSEWHEEL: - _sapp_win32_scroll_event(0.0f, (float)((SHORT)HIWORD(wParam))); - break; - case WM_MOUSEHWHEEL: - _sapp_win32_scroll_event((float)((SHORT)HIWORD(wParam)), 0.0f); - break; - case WM_CHAR: - _sapp_win32_char_event((uint32_t)wParam, !!(lParam&0x40000000)); - break; - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - _sapp_win32_key_event(SAPP_EVENTTYPE_KEY_DOWN, (int)(HIWORD(lParam)&0x1FF), !!(lParam&0x40000000)); - break; - case WM_KEYUP: - case WM_SYSKEYUP: - _sapp_win32_key_event(SAPP_EVENTTYPE_KEY_UP, (int)(HIWORD(lParam)&0x1FF), false); - break; - case WM_ENTERSIZEMOVE: - SetTimer(_sapp.win32.hwnd, 1, USER_TIMER_MINIMUM, NULL); - break; - case WM_EXITSIZEMOVE: - KillTimer(_sapp.win32.hwnd, 1); - break; - case WM_TIMER: - _sapp_win32_timing_measure(); - _sapp_frame(); - #if defined(SOKOL_D3D11) - // present with DXGI_PRESENT_DO_NOT_WAIT - _sapp_d3d11_present(true); - #endif - #if defined(SOKOL_GLCORE) - _sapp_wgl_swap_buffers(); - #endif - /* NOTE: resizing the swap-chain during resize leads to a substantial - memory spike (hundreds of megabytes for a few seconds). - - if (_sapp_win32_update_dimensions()) { - #if defined(SOKOL_D3D11) - _sapp_d3d11_resize_default_render_target(); - #endif - _sapp_win32_app_event(SAPP_EVENTTYPE_RESIZED); - } - */ - break; - case WM_NCLBUTTONDOWN: - /* workaround for half-second pause when starting to move window - see: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/ - */ - if (SendMessage(_sapp.win32.hwnd, WM_NCHITTEST, wParam, lParam) == HTCAPTION) { - POINT point; - GetCursorPos(&point); - ScreenToClient(_sapp.win32.hwnd, &point); - PostMessage(_sapp.win32.hwnd, WM_MOUSEMOVE, 0, ((uint32_t)point.x)|(((uint32_t)point.y) << 16)); - } - break; - case WM_DROPFILES: - _sapp_win32_files_dropped((HDROP)wParam); - break; - case WM_DISPLAYCHANGE: - // refresh rate might have changed - _sapp_timing_reset(&_sapp.timing); - break; - - default: - break; - } - } - return DefWindowProcW(hWnd, uMsg, wParam, lParam); -} - -_SOKOL_PRIVATE void _sapp_win32_create_window(void) { - WNDCLASSW wndclassw; - _sapp_clear(&wndclassw, sizeof(wndclassw)); - wndclassw.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wndclassw.lpfnWndProc = (WNDPROC) _sapp_win32_wndproc; - wndclassw.hInstance = GetModuleHandleW(NULL); - wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclassw.hIcon = LoadIcon(NULL, IDI_WINLOGO); - wndclassw.lpszClassName = L"SOKOLAPP"; - RegisterClassW(&wndclassw); - - /* NOTE: regardless whether fullscreen is requested or not, a regular - windowed-mode window will always be created first (however in hidden - mode, so that no windowed-mode window pops up before the fullscreen window) - */ - const DWORD win_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - RECT rect = { 0, 0, 0, 0 }; - DWORD win_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX; - rect.right = (int) ((float)_sapp.window_width * _sapp.win32.dpi.window_scale); - rect.bottom = (int) ((float)_sapp.window_height * _sapp.win32.dpi.window_scale); - const bool use_default_width = 0 == _sapp.window_width; - const bool use_default_height = 0 == _sapp.window_height; - AdjustWindowRectEx(&rect, win_style, FALSE, win_ex_style); - const int win_width = rect.right - rect.left; - const int win_height = rect.bottom - rect.top; - _sapp.win32.in_create_window = true; - _sapp.win32.hwnd = CreateWindowExW( - win_ex_style, // dwExStyle - L"SOKOLAPP", // lpClassName - _sapp.window_title_wide, // lpWindowName - win_style, // dwStyle - CW_USEDEFAULT, // X - SW_HIDE, // Y (NOTE: CW_USEDEFAULT is not used for position here, but internally calls ShowWindow! - use_default_width ? CW_USEDEFAULT : win_width, // nWidth - use_default_height ? CW_USEDEFAULT : win_height, // nHeight (NOTE: if width is CW_USEDEFAULT, height is actually ignored) - NULL, // hWndParent - NULL, // hMenu - GetModuleHandle(NULL), // hInstance - NULL); // lParam - _sapp.win32.in_create_window = false; - _sapp.win32.dc = GetDC(_sapp.win32.hwnd); - _sapp.win32.hmonitor = MonitorFromWindow(_sapp.win32.hwnd, MONITOR_DEFAULTTONULL); - SOKOL_ASSERT(_sapp.win32.dc); - - /* this will get the actual windowed-mode window size, if fullscreen - is requested, the set_fullscreen function will then capture the - current window rectangle, which then might be used later to - restore the window position when switching back to windowed - */ - _sapp_win32_update_dimensions(); - if (_sapp.fullscreen) { - _sapp_win32_set_fullscreen(_sapp.fullscreen, SWP_HIDEWINDOW); - _sapp_win32_update_dimensions(); - } - ShowWindow(_sapp.win32.hwnd, SW_SHOW); - DragAcceptFiles(_sapp.win32.hwnd, 1); -} - -_SOKOL_PRIVATE void _sapp_win32_destroy_window(void) { - DestroyWindow(_sapp.win32.hwnd); _sapp.win32.hwnd = 0; - UnregisterClassW(L"SOKOLAPP", GetModuleHandleW(NULL)); -} - -_SOKOL_PRIVATE void _sapp_win32_destroy_icons(void) { - if (_sapp.win32.big_icon) { - DestroyIcon(_sapp.win32.big_icon); - _sapp.win32.big_icon = 0; - } - if (_sapp.win32.small_icon) { - DestroyIcon(_sapp.win32.small_icon); - _sapp.win32.small_icon = 0; - } -} - -_SOKOL_PRIVATE void _sapp_win32_init_console(void) { - if (_sapp.desc.win32_console_create || _sapp.desc.win32_console_attach) { - BOOL con_valid = FALSE; - if (_sapp.desc.win32_console_create) { - con_valid = AllocConsole(); - } - else if (_sapp.desc.win32_console_attach) { - con_valid = AttachConsole(ATTACH_PARENT_PROCESS); - } - if (con_valid) { - FILE* res_fp = 0; - errno_t err; - err = freopen_s(&res_fp, "CON", "w", stdout); - (void)err; - err = freopen_s(&res_fp, "CON", "w", stderr); - (void)err; - } - } - if (_sapp.desc.win32_console_utf8) { - _sapp.win32.orig_codepage = GetConsoleOutputCP(); - SetConsoleOutputCP(CP_UTF8); - } -} - -_SOKOL_PRIVATE void _sapp_win32_restore_console(void) { - if (_sapp.desc.win32_console_utf8) { - SetConsoleOutputCP(_sapp.win32.orig_codepage); - } -} - -_SOKOL_PRIVATE void _sapp_win32_init_dpi(void) { - - DECLARE_HANDLE(DPI_AWARENESS_CONTEXT_T); - typedef BOOL(WINAPI * SETPROCESSDPIAWARE_T)(void); - typedef bool (WINAPI * SETPROCESSDPIAWARENESSCONTEXT_T)(DPI_AWARENESS_CONTEXT_T); // since Windows 10, version 1703 - typedef HRESULT(WINAPI * SETPROCESSDPIAWARENESS_T)(PROCESS_DPI_AWARENESS); - typedef HRESULT(WINAPI * GETDPIFORMONITOR_T)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); - - SETPROCESSDPIAWARE_T fn_setprocessdpiaware = 0; - SETPROCESSDPIAWARENESS_T fn_setprocessdpiawareness = 0; - GETDPIFORMONITOR_T fn_getdpiformonitor = 0; - SETPROCESSDPIAWARENESSCONTEXT_T fn_setprocessdpiawarenesscontext =0; - - HINSTANCE user32 = LoadLibraryA("user32.dll"); - if (user32) { - fn_setprocessdpiaware = (SETPROCESSDPIAWARE_T)(void*) GetProcAddress(user32, "SetProcessDPIAware"); - fn_setprocessdpiawarenesscontext = (SETPROCESSDPIAWARENESSCONTEXT_T)(void*) GetProcAddress(user32, "SetProcessDpiAwarenessContext"); - } - HINSTANCE shcore = LoadLibraryA("shcore.dll"); - if (shcore) { - fn_setprocessdpiawareness = (SETPROCESSDPIAWARENESS_T)(void*) GetProcAddress(shcore, "SetProcessDpiAwareness"); - fn_getdpiformonitor = (GETDPIFORMONITOR_T)(void*) GetProcAddress(shcore, "GetDpiForMonitor"); - } - /* - NOTE on SetProcessDpiAware() vs SetProcessDpiAwareness() vs SetProcessDpiAwarenessContext(): - - These are different attempts to get DPI handling on Windows right, from oldest - to newest. SetProcessDpiAwarenessContext() is required for the new - DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 method. - */ - if (fn_setprocessdpiawareness) { - if (_sapp.desc.high_dpi) { - /* app requests HighDPI rendering, first try the Win10 Creator Update per-monitor-dpi awareness, - if that fails, fall back to system-dpi-awareness - */ - _sapp.win32.dpi.aware = true; - DPI_AWARENESS_CONTEXT_T per_monitor_aware_v2 = (DPI_AWARENESS_CONTEXT_T)-4; - if (!(fn_setprocessdpiawarenesscontext && fn_setprocessdpiawarenesscontext(per_monitor_aware_v2))) { - // fallback to system-dpi-aware - fn_setprocessdpiawareness(PROCESS_SYSTEM_DPI_AWARE); - } - } - else { - /* if the app didn't request HighDPI rendering, let Windows do the upscaling */ - _sapp.win32.dpi.aware = false; - fn_setprocessdpiawareness(PROCESS_DPI_UNAWARE); - } - } - else if (fn_setprocessdpiaware) { - // fallback for Windows 7 - _sapp.win32.dpi.aware = true; - fn_setprocessdpiaware(); - } - /* get dpi scale factor for main monitor */ - if (fn_getdpiformonitor && _sapp.win32.dpi.aware) { - POINT pt = { 1, 1 }; - HMONITOR hm = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); - UINT dpix, dpiy; - HRESULT hr = fn_getdpiformonitor(hm, MDT_EFFECTIVE_DPI, &dpix, &dpiy); - _SOKOL_UNUSED(hr); - SOKOL_ASSERT(SUCCEEDED(hr)); - /* clamp window scale to an integer factor */ - _sapp.win32.dpi.window_scale = (float)dpix / 96.0f; - } - else { - _sapp.win32.dpi.window_scale = 1.0f; - } - if (_sapp.desc.high_dpi) { - _sapp.win32.dpi.content_scale = _sapp.win32.dpi.window_scale; - _sapp.win32.dpi.mouse_scale = 1.0f; - } - else { - _sapp.win32.dpi.content_scale = 1.0f; - _sapp.win32.dpi.mouse_scale = 1.0f / _sapp.win32.dpi.window_scale; - } - _sapp.dpi_scale = _sapp.win32.dpi.content_scale; - if (user32) { - FreeLibrary(user32); - } - if (shcore) { - FreeLibrary(shcore); - } -} - -_SOKOL_PRIVATE bool _sapp_win32_set_clipboard_string(const char* str) { - SOKOL_ASSERT(str); - SOKOL_ASSERT(_sapp.win32.hwnd); - SOKOL_ASSERT(_sapp.clipboard.enabled && (_sapp.clipboard.buf_size > 0)); - - if (!OpenClipboard(_sapp.win32.hwnd)) { - return false; - } - - HANDLE object = 0; - wchar_t* wchar_buf = 0; - - const SIZE_T wchar_buf_size = (SIZE_T)_sapp.clipboard.buf_size * sizeof(wchar_t); - object = GlobalAlloc(GMEM_MOVEABLE, wchar_buf_size); - if (NULL == object) { - goto error; - } - wchar_buf = (wchar_t*) GlobalLock(object); - if (NULL == wchar_buf) { - goto error; - } - if (!_sapp_win32_utf8_to_wide(str, wchar_buf, (int)wchar_buf_size)) { - goto error; - } - GlobalUnlock(object); - wchar_buf = 0; - EmptyClipboard(); - // NOTE: when successful, SetClipboardData() takes ownership of memory object! - if (NULL == SetClipboardData(CF_UNICODETEXT, object)) { - goto error; - } - CloseClipboard(); - return true; - -error: - if (wchar_buf) { - GlobalUnlock(object); - } - if (object) { - GlobalFree(object); - } - CloseClipboard(); - return false; -} - -_SOKOL_PRIVATE const char* _sapp_win32_get_clipboard_string(void) { - SOKOL_ASSERT(_sapp.clipboard.enabled && _sapp.clipboard.buffer); - SOKOL_ASSERT(_sapp.win32.hwnd); - if (!OpenClipboard(_sapp.win32.hwnd)) { - /* silently ignore any errors and just return the current - content of the local clipboard buffer - */ - return _sapp.clipboard.buffer; - } - HANDLE object = GetClipboardData(CF_UNICODETEXT); - if (!object) { - CloseClipboard(); - return _sapp.clipboard.buffer; - } - const wchar_t* wchar_buf = (const wchar_t*) GlobalLock(object); - if (!wchar_buf) { - CloseClipboard(); - return _sapp.clipboard.buffer; - } - if (!_sapp_win32_wide_to_utf8(wchar_buf, _sapp.clipboard.buffer, _sapp.clipboard.buf_size)) { - _SAPP_ERROR(CLIPBOARD_STRING_TOO_BIG); - } - GlobalUnlock(object); - CloseClipboard(); - return _sapp.clipboard.buffer; -} - -_SOKOL_PRIVATE void _sapp_win32_update_window_title(void) { - _sapp_win32_utf8_to_wide(_sapp.window_title, _sapp.window_title_wide, sizeof(_sapp.window_title_wide)); - SetWindowTextW(_sapp.win32.hwnd, _sapp.window_title_wide); -} - -_SOKOL_PRIVATE HICON _sapp_win32_create_icon_from_image(const sapp_image_desc* desc) { - BITMAPV5HEADER bi; - _sapp_clear(&bi, sizeof(bi)); - bi.bV5Size = sizeof(bi); - bi.bV5Width = desc->width; - bi.bV5Height = -desc->height; // NOTE the '-' here to indicate that origin is top-left - bi.bV5Planes = 1; - bi.bV5BitCount = 32; - bi.bV5Compression = BI_BITFIELDS; - bi.bV5RedMask = 0x00FF0000; - bi.bV5GreenMask = 0x0000FF00; - bi.bV5BlueMask = 0x000000FF; - bi.bV5AlphaMask = 0xFF000000; - - uint8_t* target = 0; - const uint8_t* source = (const uint8_t*)desc->pixels.ptr; - - HDC dc = GetDC(NULL); - HBITMAP color = CreateDIBSection(dc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&target, NULL, (DWORD)0); - ReleaseDC(NULL, dc); - if (0 == color) { - return NULL; - } - SOKOL_ASSERT(target); - - HBITMAP mask = CreateBitmap(desc->width, desc->height, 1, 1, NULL); - if (0 == mask) { - DeleteObject(color); - return NULL; - } - - for (int i = 0; i < (desc->width*desc->height); i++) { - target[0] = source[2]; - target[1] = source[1]; - target[2] = source[0]; - target[3] = source[3]; - target += 4; - source += 4; - } - - ICONINFO icon_info; - _sapp_clear(&icon_info, sizeof(icon_info)); - icon_info.fIcon = true; - icon_info.xHotspot = 0; - icon_info.yHotspot = 0; - icon_info.hbmMask = mask; - icon_info.hbmColor = color; - HICON icon_handle = CreateIconIndirect(&icon_info); - DeleteObject(color); - DeleteObject(mask); - - return icon_handle; -} - -_SOKOL_PRIVATE void _sapp_win32_set_icon(const sapp_icon_desc* icon_desc, int num_images) { - SOKOL_ASSERT((num_images > 0) && (num_images <= SAPP_MAX_ICONIMAGES)); - - int big_img_index = _sapp_image_bestmatch(icon_desc->images, num_images, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); - int sml_img_index = _sapp_image_bestmatch(icon_desc->images, num_images, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); - HICON big_icon = _sapp_win32_create_icon_from_image(&icon_desc->images[big_img_index]); - HICON sml_icon = _sapp_win32_create_icon_from_image(&icon_desc->images[sml_img_index]); - - // if icon creation or lookup has failed for some reason, leave the currently set icon untouched - if (0 != big_icon) { - SendMessage(_sapp.win32.hwnd, WM_SETICON, ICON_BIG, (LPARAM) big_icon); - if (0 != _sapp.win32.big_icon) { - DestroyIcon(_sapp.win32.big_icon); - } - _sapp.win32.big_icon = big_icon; - } - if (0 != sml_icon) { - SendMessage(_sapp.win32.hwnd, WM_SETICON, ICON_SMALL, (LPARAM) sml_icon); - if (0 != _sapp.win32.small_icon) { - DestroyIcon(_sapp.win32.small_icon); - } - _sapp.win32.small_icon = sml_icon; - } -} - -/* don't laugh, but this seems to be the easiest and most robust - way to check if we're running on Win10 - - From: https://github.com/videolan/vlc/blob/232fb13b0d6110c4d1b683cde24cf9a7f2c5c2ea/modules/video_output/win32/d3d11_swapchain.c#L263 -*/ -_SOKOL_PRIVATE bool _sapp_win32_is_win10_or_greater(void) { - HMODULE h = GetModuleHandleW(L"kernel32.dll"); - if (NULL != h) { - return (NULL != GetProcAddress(h, "GetSystemCpuSetInformation")); - } - else { - return false; - } -} - -_SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { - _sapp_init_state(desc); - _sapp_win32_init_console(); - _sapp.win32.is_win10_or_greater = _sapp_win32_is_win10_or_greater(); - _sapp_win32_init_keytable(); - _sapp_win32_utf8_to_wide(_sapp.window_title, _sapp.window_title_wide, sizeof(_sapp.window_title_wide)); - _sapp_win32_init_dpi(); - _sapp_win32_init_cursors(); - _sapp_win32_create_window(); - sapp_set_icon(&desc->icon); - #if defined(SOKOL_D3D11) - _sapp_d3d11_create_device_and_swapchain(); - _sapp_d3d11_create_default_render_target(); - #endif - #if defined(SOKOL_GLCORE) - _sapp_wgl_init(); - _sapp_wgl_load_extensions(); - _sapp_wgl_create_context(); - #endif - _sapp.valid = true; - - bool done = false; - while (!(done || _sapp.quit_ordered)) { - _sapp_win32_timing_measure(); - MSG msg; - while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { - if (WM_QUIT == msg.message) { - done = true; - continue; - } - else { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } - _sapp_frame(); - #if defined(SOKOL_D3D11) - _sapp_d3d11_present(false); - if (IsIconic(_sapp.win32.hwnd)) { - Sleep((DWORD)(16 * _sapp.swap_interval)); - } - #endif - #if defined(SOKOL_GLCORE) - _sapp_wgl_swap_buffers(); - #endif - /* check for window resized, this cannot happen in WM_SIZE as it explodes memory usage */ - if (_sapp_win32_update_dimensions()) { - #if defined(SOKOL_D3D11) - _sapp_d3d11_resize_default_render_target(); - #endif - _sapp_win32_app_event(SAPP_EVENTTYPE_RESIZED); - } - /* check if the window monitor has changed, need to reset timing because - the new monitor might have a different refresh rate - */ - if (_sapp_win32_update_monitor()) { - _sapp_timing_reset(&_sapp.timing); - } - if (_sapp.quit_requested) { - PostMessage(_sapp.win32.hwnd, WM_CLOSE, 0, 0); - } - } - _sapp_call_cleanup(); - - #if defined(SOKOL_D3D11) - _sapp_d3d11_destroy_default_render_target(); - _sapp_d3d11_destroy_device_and_swapchain(); - #elif defined(SOKOL_GLCORE) - _sapp_wgl_destroy_context(); - _sapp_wgl_shutdown(); - #endif - _sapp_win32_destroy_window(); - _sapp_win32_destroy_icons(); - _sapp_win32_restore_console(); - _sapp_discard_state(); -} - -_SOKOL_PRIVATE char** _sapp_win32_command_line_to_utf8_argv(LPWSTR w_command_line, int* o_argc) { - int argc = 0; - char** argv = 0; - char* args; - - LPWSTR* w_argv = CommandLineToArgvW(w_command_line, &argc); - if (w_argv == NULL) { - // FIXME: chicken egg problem, can't report errors before sokol_main() is called! - } else { - size_t size = wcslen(w_command_line) * 4; - argv = (char**) _sapp_malloc_clear(((size_t)argc + 1) * sizeof(char*) + size); - SOKOL_ASSERT(argv); - args = (char*) &argv[argc + 1]; - int n; - for (int i = 0; i < argc; ++i) { - n = WideCharToMultiByte(CP_UTF8, 0, w_argv[i], -1, args, (int)size, NULL, NULL); - if (n == 0) { - // FIXME: chicken egg problem, can't report errors before sokol_main() is called! - break; - } - argv[i] = args; - size -= (size_t)n; - args += n; - } - LocalFree(w_argv); - } - *o_argc = argc; - return argv; -} - -#if !defined(SOKOL_NO_ENTRY) -#if defined(SOKOL_WIN32_FORCE_MAIN) -int main(int argc, char* argv[]) { - sapp_desc desc = sokol_main(argc, argv); - _sapp_win32_run(&desc); - return 0; -} -#else -int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) { - _SOKOL_UNUSED(hInstance); - _SOKOL_UNUSED(hPrevInstance); - _SOKOL_UNUSED(lpCmdLine); - _SOKOL_UNUSED(nCmdShow); - int argc_utf8 = 0; - char** argv_utf8 = _sapp_win32_command_line_to_utf8_argv(GetCommandLineW(), &argc_utf8); - sapp_desc desc = sokol_main(argc_utf8, argv_utf8); - _sapp_win32_run(&desc); - _sapp_free(argv_utf8); - return 0; -} -#endif /* SOKOL_WIN32_FORCE_MAIN */ -#endif /* SOKOL_NO_ENTRY */ - -#ifdef _MSC_VER - #pragma warning(pop) -#endif - -#endif /* _SAPP_WIN32 */ - -// █████ ███ ██ ██████ ██████ ██████ ██ ██████ -// ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ████ ██████ ██ ██ ██████ ██ ██████ -// -// >>android -#if defined(_SAPP_ANDROID) - -/* android loop thread */ -_SOKOL_PRIVATE bool _sapp_android_init_egl(void) { - SOKOL_ASSERT(_sapp.android.display == EGL_NO_DISPLAY); - SOKOL_ASSERT(_sapp.android.context == EGL_NO_CONTEXT); - - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (display == EGL_NO_DISPLAY) { - return false; - } - if (eglInitialize(display, NULL, NULL) == EGL_FALSE) { - return false; - } - EGLint alpha_size = _sapp.desc.alpha ? 8 : 0; - const EGLint cfg_attributes[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, alpha_size, - EGL_DEPTH_SIZE, 16, - EGL_STENCIL_SIZE, 0, - EGL_NONE, - }; - EGLConfig available_cfgs[32]; - EGLint cfg_count; - eglChooseConfig(display, cfg_attributes, available_cfgs, 32, &cfg_count); - SOKOL_ASSERT(cfg_count > 0); - SOKOL_ASSERT(cfg_count <= 32); - - /* find config with 8-bit rgb buffer if available, ndk sample does not trust egl spec */ - EGLConfig config; - bool exact_cfg_found = false; - for (int i = 0; i < cfg_count; ++i) { - EGLConfig c = available_cfgs[i]; - EGLint r, g, b, a, d; - if (eglGetConfigAttrib(display, c, EGL_RED_SIZE, &r) == EGL_TRUE && - eglGetConfigAttrib(display, c, EGL_GREEN_SIZE, &g) == EGL_TRUE && - eglGetConfigAttrib(display, c, EGL_BLUE_SIZE, &b) == EGL_TRUE && - eglGetConfigAttrib(display, c, EGL_ALPHA_SIZE, &a) == EGL_TRUE && - eglGetConfigAttrib(display, c, EGL_DEPTH_SIZE, &d) == EGL_TRUE && - r == 8 && g == 8 && b == 8 && (alpha_size == 0 || a == alpha_size) && d == 16) { - exact_cfg_found = true; - config = c; - break; - } - } - if (!exact_cfg_found) { - config = available_cfgs[0]; - } - - EGLint ctx_attributes[] = { - EGL_CONTEXT_CLIENT_VERSION, 3, - EGL_NONE, - }; - EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attributes); - if (context == EGL_NO_CONTEXT) { - return false; - } - - _sapp.android.config = config; - _sapp.android.display = display; - _sapp.android.context = context; - return true; -} - -_SOKOL_PRIVATE void _sapp_android_cleanup_egl(void) { - if (_sapp.android.display != EGL_NO_DISPLAY) { - eglMakeCurrent(_sapp.android.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (_sapp.android.surface != EGL_NO_SURFACE) { - eglDestroySurface(_sapp.android.display, _sapp.android.surface); - _sapp.android.surface = EGL_NO_SURFACE; - } - if (_sapp.android.context != EGL_NO_CONTEXT) { - eglDestroyContext(_sapp.android.display, _sapp.android.context); - _sapp.android.context = EGL_NO_CONTEXT; - } - eglTerminate(_sapp.android.display); - _sapp.android.display = EGL_NO_DISPLAY; - } -} - -_SOKOL_PRIVATE bool _sapp_android_init_egl_surface(ANativeWindow* window) { - SOKOL_ASSERT(_sapp.android.display != EGL_NO_DISPLAY); - SOKOL_ASSERT(_sapp.android.context != EGL_NO_CONTEXT); - SOKOL_ASSERT(_sapp.android.surface == EGL_NO_SURFACE); - SOKOL_ASSERT(window); - - /* TODO: set window flags */ - /* ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON, 0); */ - - /* create egl surface and make it current */ - EGLSurface surface = eglCreateWindowSurface(_sapp.android.display, _sapp.android.config, window, NULL); - if (surface == EGL_NO_SURFACE) { - return false; - } - if (eglMakeCurrent(_sapp.android.display, surface, surface, _sapp.android.context) == EGL_FALSE) { - return false; - } - _sapp.android.surface = surface; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); - return true; -} - -_SOKOL_PRIVATE void _sapp_android_cleanup_egl_surface(void) { - if (_sapp.android.display == EGL_NO_DISPLAY) { - return; - } - eglMakeCurrent(_sapp.android.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (_sapp.android.surface != EGL_NO_SURFACE) { - eglDestroySurface(_sapp.android.display, _sapp.android.surface); - _sapp.android.surface = EGL_NO_SURFACE; - } -} - -_SOKOL_PRIVATE void _sapp_android_app_event(sapp_event_type type) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_android_update_dimensions(ANativeWindow* window, bool force_update) { - SOKOL_ASSERT(_sapp.android.display != EGL_NO_DISPLAY); - SOKOL_ASSERT(_sapp.android.context != EGL_NO_CONTEXT); - SOKOL_ASSERT(_sapp.android.surface != EGL_NO_SURFACE); - SOKOL_ASSERT(window); - - const int32_t win_w = ANativeWindow_getWidth(window); - const int32_t win_h = ANativeWindow_getHeight(window); - SOKOL_ASSERT(win_w >= 0 && win_h >= 0); - const bool win_changed = (win_w != _sapp.window_width) || (win_h != _sapp.window_height); - _sapp.window_width = win_w; - _sapp.window_height = win_h; - if (win_changed || force_update) { - if (!_sapp.desc.high_dpi) { - const int32_t buf_w = win_w / 2; - const int32_t buf_h = win_h / 2; - EGLint format; - EGLBoolean egl_result = eglGetConfigAttrib(_sapp.android.display, _sapp.android.config, EGL_NATIVE_VISUAL_ID, &format); - SOKOL_ASSERT(egl_result == EGL_TRUE); _SOKOL_UNUSED(egl_result); - /* NOTE: calling ANativeWindow_setBuffersGeometry() with the same dimensions - as the ANativeWindow size results in weird display artefacts, that's - why it's only called when the buffer geometry is different from - the window size - */ - int32_t result = ANativeWindow_setBuffersGeometry(window, buf_w, buf_h, format); - SOKOL_ASSERT(result == 0); _SOKOL_UNUSED(result); - } - } - - /* query surface size */ - EGLint fb_w, fb_h; - EGLBoolean egl_result_w = eglQuerySurface(_sapp.android.display, _sapp.android.surface, EGL_WIDTH, &fb_w); - EGLBoolean egl_result_h = eglQuerySurface(_sapp.android.display, _sapp.android.surface, EGL_HEIGHT, &fb_h); - SOKOL_ASSERT(egl_result_w == EGL_TRUE); _SOKOL_UNUSED(egl_result_w); - SOKOL_ASSERT(egl_result_h == EGL_TRUE); _SOKOL_UNUSED(egl_result_h); - const bool fb_changed = (fb_w != _sapp.framebuffer_width) || (fb_h != _sapp.framebuffer_height); - _sapp.framebuffer_width = fb_w; - _sapp.framebuffer_height = fb_h; - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float)_sapp.window_width; - if (win_changed || fb_changed || force_update) { - if (!_sapp.first_frame) { - _sapp_android_app_event(SAPP_EVENTTYPE_RESIZED); - } - } -} - -_SOKOL_PRIVATE void _sapp_android_cleanup(void) { - if (_sapp.android.surface != EGL_NO_SURFACE) { - /* egl context is bound, cleanup gracefully */ - if (_sapp.init_called && !_sapp.cleanup_called) { - _sapp_call_cleanup(); - } - } - /* always try to cleanup by destroying egl context */ - _sapp_android_cleanup_egl(); -} - -_SOKOL_PRIVATE void _sapp_android_shutdown(void) { - /* try to cleanup while we still have a surface and can call cleanup_cb() */ - _sapp_android_cleanup(); - /* request exit */ - ANativeActivity_finish(_sapp.android.activity); -} - -_SOKOL_PRIVATE void _sapp_android_frame(void) { - SOKOL_ASSERT(_sapp.android.display != EGL_NO_DISPLAY); - SOKOL_ASSERT(_sapp.android.context != EGL_NO_CONTEXT); - SOKOL_ASSERT(_sapp.android.surface != EGL_NO_SURFACE); - _sapp_timing_measure(&_sapp.timing); - _sapp_android_update_dimensions(_sapp.android.current.window, false); - _sapp_frame(); - eglSwapBuffers(_sapp.android.display, _sapp.android.surface); -} - -_SOKOL_PRIVATE bool _sapp_android_touch_event(const AInputEvent* e) { - if (AInputEvent_getType(e) != AINPUT_EVENT_TYPE_MOTION) { - return false; - } - if (!_sapp_events_enabled()) { - return false; - } - int32_t action_idx = AMotionEvent_getAction(e); - int32_t action = action_idx & AMOTION_EVENT_ACTION_MASK; - sapp_event_type type = SAPP_EVENTTYPE_INVALID; - switch (action) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - type = SAPP_EVENTTYPE_TOUCHES_BEGAN; - break; - case AMOTION_EVENT_ACTION_MOVE: - type = SAPP_EVENTTYPE_TOUCHES_MOVED; - break; - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_POINTER_UP: - type = SAPP_EVENTTYPE_TOUCHES_ENDED; - break; - case AMOTION_EVENT_ACTION_CANCEL: - type = SAPP_EVENTTYPE_TOUCHES_CANCELLED; - break; - default: - break; - } - if (type == SAPP_EVENTTYPE_INVALID) { - return false; - } - int32_t idx = action_idx >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - _sapp_init_event(type); - _sapp.event.num_touches = (int)AMotionEvent_getPointerCount(e); - if (_sapp.event.num_touches > SAPP_MAX_TOUCHPOINTS) { - _sapp.event.num_touches = SAPP_MAX_TOUCHPOINTS; - } - for (int32_t i = 0; i < _sapp.event.num_touches; i++) { - sapp_touchpoint* dst = &_sapp.event.touches[i]; - dst->identifier = (uintptr_t)AMotionEvent_getPointerId(e, (size_t)i); - dst->pos_x = (AMotionEvent_getX(e, (size_t)i) / _sapp.window_width) * _sapp.framebuffer_width; - dst->pos_y = (AMotionEvent_getY(e, (size_t)i) / _sapp.window_height) * _sapp.framebuffer_height; - dst->android_tooltype = (sapp_android_tooltype) AMotionEvent_getToolType(e, (size_t)i); - if (action == AMOTION_EVENT_ACTION_POINTER_DOWN || - action == AMOTION_EVENT_ACTION_POINTER_UP) { - dst->changed = (i == idx); - } else { - dst->changed = true; - } - } - _sapp_call_event(&_sapp.event); - return true; -} - -_SOKOL_PRIVATE bool _sapp_android_key_event(const AInputEvent* e) { - if (AInputEvent_getType(e) != AINPUT_EVENT_TYPE_KEY) { - return false; - } - if (AKeyEvent_getKeyCode(e) == AKEYCODE_BACK) { - /* FIXME: this should be hooked into a "really quit?" mechanism - so the app can ask the user for confirmation, this is currently - generally missing in sokol_app.h - */ - _sapp_android_shutdown(); - return true; - } - return false; -} - -_SOKOL_PRIVATE int _sapp_android_input_cb(int fd, int events, void* data) { - _SOKOL_UNUSED(fd); - _SOKOL_UNUSED(data); - if ((events & ALOOPER_EVENT_INPUT) == 0) { - _SAPP_ERROR(ANDROID_UNSUPPORTED_INPUT_EVENT_INPUT_CB); - return 1; - } - SOKOL_ASSERT(_sapp.android.current.input); - AInputEvent* event = NULL; - while (AInputQueue_getEvent(_sapp.android.current.input, &event) >= 0) { - if (AInputQueue_preDispatchEvent(_sapp.android.current.input, event) != 0) { - continue; - } - int32_t handled = 0; - if (_sapp_android_touch_event(event) || _sapp_android_key_event(event)) { - handled = 1; - } - AInputQueue_finishEvent(_sapp.android.current.input, event, handled); - } - return 1; -} - -_SOKOL_PRIVATE int _sapp_android_main_cb(int fd, int events, void* data) { - _SOKOL_UNUSED(data); - if ((events & ALOOPER_EVENT_INPUT) == 0) { - _SAPP_ERROR(ANDROID_UNSUPPORTED_INPUT_EVENT_MAIN_CB); - return 1; - } - - _sapp_android_msg_t msg; - if (read(fd, &msg, sizeof(msg)) != sizeof(msg)) { - _SAPP_ERROR(ANDROID_READ_MSG_FAILED); - return 1; - } - - pthread_mutex_lock(&_sapp.android.pt.mutex); - switch (msg) { - case _SOKOL_ANDROID_MSG_CREATE: - { - _SAPP_INFO(ANDROID_MSG_CREATE); - SOKOL_ASSERT(!_sapp.valid); - bool result = _sapp_android_init_egl(); - SOKOL_ASSERT(result); _SOKOL_UNUSED(result); - _sapp.valid = true; - _sapp.android.has_created = true; - } - break; - case _SOKOL_ANDROID_MSG_RESUME: - _SAPP_INFO(ANDROID_MSG_RESUME); - _sapp.android.has_resumed = true; - _sapp_android_app_event(SAPP_EVENTTYPE_RESUMED); - break; - case _SOKOL_ANDROID_MSG_PAUSE: - _SAPP_INFO(ANDROID_MSG_PAUSE); - _sapp.android.has_resumed = false; - _sapp_android_app_event(SAPP_EVENTTYPE_SUSPENDED); - break; - case _SOKOL_ANDROID_MSG_FOCUS: - _SAPP_INFO(ANDROID_MSG_FOCUS); - _sapp.android.has_focus = true; - break; - case _SOKOL_ANDROID_MSG_NO_FOCUS: - _SAPP_INFO(ANDROID_MSG_NO_FOCUS); - _sapp.android.has_focus = false; - break; - case _SOKOL_ANDROID_MSG_SET_NATIVE_WINDOW: - _SAPP_INFO(ANDROID_MSG_SET_NATIVE_WINDOW); - if (_sapp.android.current.window != _sapp.android.pending.window) { - if (_sapp.android.current.window != NULL) { - _sapp_android_cleanup_egl_surface(); - } - if (_sapp.android.pending.window != NULL) { - if (_sapp_android_init_egl_surface(_sapp.android.pending.window)) { - _sapp_android_update_dimensions(_sapp.android.pending.window, true); - } else { - _sapp_android_shutdown(); - } - } - } - _sapp.android.current.window = _sapp.android.pending.window; - break; - case _SOKOL_ANDROID_MSG_SET_INPUT_QUEUE: - _SAPP_INFO(ANDROID_MSG_SET_INPUT_QUEUE); - if (_sapp.android.current.input != _sapp.android.pending.input) { - if (_sapp.android.current.input != NULL) { - AInputQueue_detachLooper(_sapp.android.current.input); - } - if (_sapp.android.pending.input != NULL) { - AInputQueue_attachLooper( - _sapp.android.pending.input, - _sapp.android.looper, - ALOOPER_POLL_CALLBACK, - _sapp_android_input_cb, - NULL); /* data */ - } - } - _sapp.android.current.input = _sapp.android.pending.input; - break; - case _SOKOL_ANDROID_MSG_DESTROY: - _SAPP_INFO(ANDROID_MSG_DESTROY); - _sapp_android_cleanup(); - _sapp.valid = false; - _sapp.android.is_thread_stopping = true; - break; - default: - _SAPP_WARN(ANDROID_UNKNOWN_MSG); - break; - } - pthread_cond_broadcast(&_sapp.android.pt.cond); /* signal "received" */ - pthread_mutex_unlock(&_sapp.android.pt.mutex); - return 1; -} - -_SOKOL_PRIVATE bool _sapp_android_should_update(void) { - bool is_in_front = _sapp.android.has_resumed && _sapp.android.has_focus; - bool has_surface = _sapp.android.surface != EGL_NO_SURFACE; - return is_in_front && has_surface; -} - -_SOKOL_PRIVATE void _sapp_android_show_keyboard(bool shown) { - SOKOL_ASSERT(_sapp.valid); - /* This seems to be broken in the NDK, but there is (a very cumbersome) workaround... */ - if (shown) { - ANativeActivity_showSoftInput(_sapp.android.activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED); - } else { - ANativeActivity_hideSoftInput(_sapp.android.activity, ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS); - } -} - -_SOKOL_PRIVATE void* _sapp_android_loop(void* arg) { - _SOKOL_UNUSED(arg); - _SAPP_INFO(ANDROID_LOOP_THREAD_STARTED); - - _sapp.android.looper = ALooper_prepare(0 /* or ALOOPER_PREPARE_ALLOW_NON_CALLBACKS*/); - ALooper_addFd(_sapp.android.looper, - _sapp.android.pt.read_from_main_fd, - ALOOPER_POLL_CALLBACK, - ALOOPER_EVENT_INPUT, - _sapp_android_main_cb, - NULL); /* data */ - - /* signal start to main thread */ - pthread_mutex_lock(&_sapp.android.pt.mutex); - _sapp.android.is_thread_started = true; - pthread_cond_broadcast(&_sapp.android.pt.cond); - pthread_mutex_unlock(&_sapp.android.pt.mutex); - - /* main loop */ - while (!_sapp.android.is_thread_stopping) { - /* sokol frame */ - if (_sapp_android_should_update()) { - _sapp_android_frame(); - } - - /* process all events (or stop early if app is requested to quit) */ - bool process_events = true; - while (process_events && !_sapp.android.is_thread_stopping) { - bool block_until_event = !_sapp.android.is_thread_stopping && !_sapp_android_should_update(); - process_events = ALooper_pollOnce(block_until_event ? -1 : 0, NULL, NULL, NULL) == ALOOPER_POLL_CALLBACK; - } - } - - /* cleanup thread */ - if (_sapp.android.current.input != NULL) { - AInputQueue_detachLooper(_sapp.android.current.input); - } - - /* the following causes heap corruption on exit, why?? - ALooper_removeFd(_sapp.android.looper, _sapp.android.pt.read_from_main_fd); - ALooper_release(_sapp.android.looper);*/ - - /* signal "destroyed" */ - pthread_mutex_lock(&_sapp.android.pt.mutex); - _sapp.android.is_thread_stopped = true; - pthread_cond_broadcast(&_sapp.android.pt.cond); - pthread_mutex_unlock(&_sapp.android.pt.mutex); - - _SAPP_INFO(ANDROID_LOOP_THREAD_DONE); - return NULL; -} - -/* android main/ui thread */ -_SOKOL_PRIVATE void _sapp_android_msg(_sapp_android_msg_t msg) { - if (write(_sapp.android.pt.write_from_main_fd, &msg, sizeof(msg)) != sizeof(msg)) { - _SAPP_ERROR(ANDROID_WRITE_MSG_FAILED); - } -} - -_SOKOL_PRIVATE void _sapp_android_on_start(ANativeActivity* activity) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONSTART); -} - -_SOKOL_PRIVATE void _sapp_android_on_resume(ANativeActivity* activity) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONRESUME); - _sapp_android_msg(_SOKOL_ANDROID_MSG_RESUME); -} - -_SOKOL_PRIVATE void* _sapp_android_on_save_instance_state(ANativeActivity* activity, size_t* out_size) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONSAVEINSTANCESTATE); - *out_size = 0; - return NULL; -} - -_SOKOL_PRIVATE void _sapp_android_on_window_focus_changed(ANativeActivity* activity, int has_focus) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONWINDOWFOCUSCHANGED); - if (has_focus) { - _sapp_android_msg(_SOKOL_ANDROID_MSG_FOCUS); - } else { - _sapp_android_msg(_SOKOL_ANDROID_MSG_NO_FOCUS); - } -} - -_SOKOL_PRIVATE void _sapp_android_on_pause(ANativeActivity* activity) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONPAUSE); - _sapp_android_msg(_SOKOL_ANDROID_MSG_PAUSE); -} - -_SOKOL_PRIVATE void _sapp_android_on_stop(ANativeActivity* activity) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONSTOP); -} - -_SOKOL_PRIVATE void _sapp_android_msg_set_native_window(ANativeWindow* window) { - pthread_mutex_lock(&_sapp.android.pt.mutex); - _sapp.android.pending.window = window; - _sapp_android_msg(_SOKOL_ANDROID_MSG_SET_NATIVE_WINDOW); - while (_sapp.android.current.window != window) { - pthread_cond_wait(&_sapp.android.pt.cond, &_sapp.android.pt.mutex); - } - pthread_mutex_unlock(&_sapp.android.pt.mutex); -} - -_SOKOL_PRIVATE void _sapp_android_on_native_window_created(ANativeActivity* activity, ANativeWindow* window) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONNATIVEWINDOWCREATED); - _sapp_android_msg_set_native_window(window); -} - -_SOKOL_PRIVATE void _sapp_android_on_native_window_destroyed(ANativeActivity* activity, ANativeWindow* window) { - _SOKOL_UNUSED(activity); - _SOKOL_UNUSED(window); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONNATIVEWINDOWDESTROYED); - _sapp_android_msg_set_native_window(NULL); -} - -_SOKOL_PRIVATE void _sapp_android_msg_set_input_queue(AInputQueue* input) { - pthread_mutex_lock(&_sapp.android.pt.mutex); - _sapp.android.pending.input = input; - _sapp_android_msg(_SOKOL_ANDROID_MSG_SET_INPUT_QUEUE); - while (_sapp.android.current.input != input) { - pthread_cond_wait(&_sapp.android.pt.cond, &_sapp.android.pt.mutex); - } - pthread_mutex_unlock(&_sapp.android.pt.mutex); -} - -_SOKOL_PRIVATE void _sapp_android_on_input_queue_created(ANativeActivity* activity, AInputQueue* queue) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONINPUTQUEUECREATED); - _sapp_android_msg_set_input_queue(queue); -} - -_SOKOL_PRIVATE void _sapp_android_on_input_queue_destroyed(ANativeActivity* activity, AInputQueue* queue) { - _SOKOL_UNUSED(activity); - _SOKOL_UNUSED(queue); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONINPUTQUEUEDESTROYED); - _sapp_android_msg_set_input_queue(NULL); -} - -_SOKOL_PRIVATE void _sapp_android_on_config_changed(ANativeActivity* activity) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONCONFIGURATIONCHANGED); - /* see android:configChanges in manifest */ -} - -_SOKOL_PRIVATE void _sapp_android_on_low_memory(ANativeActivity* activity) { - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONLOWMEMORY); -} - -_SOKOL_PRIVATE void _sapp_android_on_destroy(ANativeActivity* activity) { - /* - * For some reason even an empty app using nativeactivity.h will crash (WIN DEATH) - * on my device (Moto X 2nd gen) when the app is removed from the task view - * (TaskStackView: onTaskViewDismissed). - * - * However, if ANativeActivity_finish() is explicitly called from for example - * _sapp_android_on_stop(), the crash disappears. Is this a bug in NativeActivity? - */ - _SOKOL_UNUSED(activity); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONDESTROY); - - /* send destroy msg */ - pthread_mutex_lock(&_sapp.android.pt.mutex); - _sapp_android_msg(_SOKOL_ANDROID_MSG_DESTROY); - while (!_sapp.android.is_thread_stopped) { - pthread_cond_wait(&_sapp.android.pt.cond, &_sapp.android.pt.mutex); - } - pthread_mutex_unlock(&_sapp.android.pt.mutex); - - /* clean up main thread */ - pthread_cond_destroy(&_sapp.android.pt.cond); - pthread_mutex_destroy(&_sapp.android.pt.mutex); - - close(_sapp.android.pt.read_from_main_fd); - close(_sapp.android.pt.write_from_main_fd); - - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_DONE); - - /* this is a bit naughty, but causes a clean restart of the app (static globals are reset) */ - exit(0); -} - -JNIEXPORT -void ANativeActivity_onCreate(ANativeActivity* activity, void* saved_state, size_t saved_state_size) { - _SOKOL_UNUSED(saved_state); - _SOKOL_UNUSED(saved_state_size); - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_ONCREATE); - - // the NativeActity pointer needs to be available inside sokol_main() - // (see https://github.com/floooh/sokol/issues/708), however _sapp_init_state() - // will clear the global _sapp_t struct, so we need to initialize the native - // activity pointer twice, once before sokol_main() and once after _sapp_init_state() - _sapp_clear(&_sapp, sizeof(_sapp)); - _sapp.android.activity = activity; - sapp_desc desc = sokol_main(0, NULL); - _sapp_init_state(&desc); - _sapp.android.activity = activity; - - int pipe_fd[2]; - if (pipe(pipe_fd) != 0) { - _SAPP_ERROR(ANDROID_CREATE_THREAD_PIPE_FAILED); - return; - } - _sapp.android.pt.read_from_main_fd = pipe_fd[0]; - _sapp.android.pt.write_from_main_fd = pipe_fd[1]; - - pthread_mutex_init(&_sapp.android.pt.mutex, NULL); - pthread_cond_init(&_sapp.android.pt.cond, NULL); - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&_sapp.android.pt.thread, &attr, _sapp_android_loop, 0); - pthread_attr_destroy(&attr); - - /* wait until main loop has started */ - pthread_mutex_lock(&_sapp.android.pt.mutex); - while (!_sapp.android.is_thread_started) { - pthread_cond_wait(&_sapp.android.pt.cond, &_sapp.android.pt.mutex); - } - pthread_mutex_unlock(&_sapp.android.pt.mutex); - - /* send create msg */ - pthread_mutex_lock(&_sapp.android.pt.mutex); - _sapp_android_msg(_SOKOL_ANDROID_MSG_CREATE); - while (!_sapp.android.has_created) { - pthread_cond_wait(&_sapp.android.pt.cond, &_sapp.android.pt.mutex); - } - pthread_mutex_unlock(&_sapp.android.pt.mutex); - - /* register for callbacks */ - activity->callbacks->onStart = _sapp_android_on_start; - activity->callbacks->onResume = _sapp_android_on_resume; - activity->callbacks->onSaveInstanceState = _sapp_android_on_save_instance_state; - activity->callbacks->onWindowFocusChanged = _sapp_android_on_window_focus_changed; - activity->callbacks->onPause = _sapp_android_on_pause; - activity->callbacks->onStop = _sapp_android_on_stop; - activity->callbacks->onDestroy = _sapp_android_on_destroy; - activity->callbacks->onNativeWindowCreated = _sapp_android_on_native_window_created; - /* activity->callbacks->onNativeWindowResized = _sapp_android_on_native_window_resized; */ - /* activity->callbacks->onNativeWindowRedrawNeeded = _sapp_android_on_native_window_redraw_needed; */ - activity->callbacks->onNativeWindowDestroyed = _sapp_android_on_native_window_destroyed; - activity->callbacks->onInputQueueCreated = _sapp_android_on_input_queue_created; - activity->callbacks->onInputQueueDestroyed = _sapp_android_on_input_queue_destroyed; - /* activity->callbacks->onContentRectChanged = _sapp_android_on_content_rect_changed; */ - activity->callbacks->onConfigurationChanged = _sapp_android_on_config_changed; - activity->callbacks->onLowMemory = _sapp_android_on_low_memory; - - _SAPP_INFO(ANDROID_NATIVE_ACTIVITY_CREATE_SUCCESS); - - /* NOT A BUG: do NOT call sapp_discard_state() */ -} - -#endif /* _SAPP_ANDROID */ - -// ██ ██ ███ ██ ██ ██ ██ ██ -// ██ ██ ████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ████ ██████ ██ ██ -// -// >>linux -#if defined(_SAPP_LINUX) - -/* see GLFW's xkb_unicode.c */ -static const struct _sapp_x11_codepair { - uint16_t keysym; - uint16_t ucs; -} _sapp_x11_keysymtab[] = { - { 0x01a1, 0x0104 }, - { 0x01a2, 0x02d8 }, - { 0x01a3, 0x0141 }, - { 0x01a5, 0x013d }, - { 0x01a6, 0x015a }, - { 0x01a9, 0x0160 }, - { 0x01aa, 0x015e }, - { 0x01ab, 0x0164 }, - { 0x01ac, 0x0179 }, - { 0x01ae, 0x017d }, - { 0x01af, 0x017b }, - { 0x01b1, 0x0105 }, - { 0x01b2, 0x02db }, - { 0x01b3, 0x0142 }, - { 0x01b5, 0x013e }, - { 0x01b6, 0x015b }, - { 0x01b7, 0x02c7 }, - { 0x01b9, 0x0161 }, - { 0x01ba, 0x015f }, - { 0x01bb, 0x0165 }, - { 0x01bc, 0x017a }, - { 0x01bd, 0x02dd }, - { 0x01be, 0x017e }, - { 0x01bf, 0x017c }, - { 0x01c0, 0x0154 }, - { 0x01c3, 0x0102 }, - { 0x01c5, 0x0139 }, - { 0x01c6, 0x0106 }, - { 0x01c8, 0x010c }, - { 0x01ca, 0x0118 }, - { 0x01cc, 0x011a }, - { 0x01cf, 0x010e }, - { 0x01d0, 0x0110 }, - { 0x01d1, 0x0143 }, - { 0x01d2, 0x0147 }, - { 0x01d5, 0x0150 }, - { 0x01d8, 0x0158 }, - { 0x01d9, 0x016e }, - { 0x01db, 0x0170 }, - { 0x01de, 0x0162 }, - { 0x01e0, 0x0155 }, - { 0x01e3, 0x0103 }, - { 0x01e5, 0x013a }, - { 0x01e6, 0x0107 }, - { 0x01e8, 0x010d }, - { 0x01ea, 0x0119 }, - { 0x01ec, 0x011b }, - { 0x01ef, 0x010f }, - { 0x01f0, 0x0111 }, - { 0x01f1, 0x0144 }, - { 0x01f2, 0x0148 }, - { 0x01f5, 0x0151 }, - { 0x01f8, 0x0159 }, - { 0x01f9, 0x016f }, - { 0x01fb, 0x0171 }, - { 0x01fe, 0x0163 }, - { 0x01ff, 0x02d9 }, - { 0x02a1, 0x0126 }, - { 0x02a6, 0x0124 }, - { 0x02a9, 0x0130 }, - { 0x02ab, 0x011e }, - { 0x02ac, 0x0134 }, - { 0x02b1, 0x0127 }, - { 0x02b6, 0x0125 }, - { 0x02b9, 0x0131 }, - { 0x02bb, 0x011f }, - { 0x02bc, 0x0135 }, - { 0x02c5, 0x010a }, - { 0x02c6, 0x0108 }, - { 0x02d5, 0x0120 }, - { 0x02d8, 0x011c }, - { 0x02dd, 0x016c }, - { 0x02de, 0x015c }, - { 0x02e5, 0x010b }, - { 0x02e6, 0x0109 }, - { 0x02f5, 0x0121 }, - { 0x02f8, 0x011d }, - { 0x02fd, 0x016d }, - { 0x02fe, 0x015d }, - { 0x03a2, 0x0138 }, - { 0x03a3, 0x0156 }, - { 0x03a5, 0x0128 }, - { 0x03a6, 0x013b }, - { 0x03aa, 0x0112 }, - { 0x03ab, 0x0122 }, - { 0x03ac, 0x0166 }, - { 0x03b3, 0x0157 }, - { 0x03b5, 0x0129 }, - { 0x03b6, 0x013c }, - { 0x03ba, 0x0113 }, - { 0x03bb, 0x0123 }, - { 0x03bc, 0x0167 }, - { 0x03bd, 0x014a }, - { 0x03bf, 0x014b }, - { 0x03c0, 0x0100 }, - { 0x03c7, 0x012e }, - { 0x03cc, 0x0116 }, - { 0x03cf, 0x012a }, - { 0x03d1, 0x0145 }, - { 0x03d2, 0x014c }, - { 0x03d3, 0x0136 }, - { 0x03d9, 0x0172 }, - { 0x03dd, 0x0168 }, - { 0x03de, 0x016a }, - { 0x03e0, 0x0101 }, - { 0x03e7, 0x012f }, - { 0x03ec, 0x0117 }, - { 0x03ef, 0x012b }, - { 0x03f1, 0x0146 }, - { 0x03f2, 0x014d }, - { 0x03f3, 0x0137 }, - { 0x03f9, 0x0173 }, - { 0x03fd, 0x0169 }, - { 0x03fe, 0x016b }, - { 0x047e, 0x203e }, - { 0x04a1, 0x3002 }, - { 0x04a2, 0x300c }, - { 0x04a3, 0x300d }, - { 0x04a4, 0x3001 }, - { 0x04a5, 0x30fb }, - { 0x04a6, 0x30f2 }, - { 0x04a7, 0x30a1 }, - { 0x04a8, 0x30a3 }, - { 0x04a9, 0x30a5 }, - { 0x04aa, 0x30a7 }, - { 0x04ab, 0x30a9 }, - { 0x04ac, 0x30e3 }, - { 0x04ad, 0x30e5 }, - { 0x04ae, 0x30e7 }, - { 0x04af, 0x30c3 }, - { 0x04b0, 0x30fc }, - { 0x04b1, 0x30a2 }, - { 0x04b2, 0x30a4 }, - { 0x04b3, 0x30a6 }, - { 0x04b4, 0x30a8 }, - { 0x04b5, 0x30aa }, - { 0x04b6, 0x30ab }, - { 0x04b7, 0x30ad }, - { 0x04b8, 0x30af }, - { 0x04b9, 0x30b1 }, - { 0x04ba, 0x30b3 }, - { 0x04bb, 0x30b5 }, - { 0x04bc, 0x30b7 }, - { 0x04bd, 0x30b9 }, - { 0x04be, 0x30bb }, - { 0x04bf, 0x30bd }, - { 0x04c0, 0x30bf }, - { 0x04c1, 0x30c1 }, - { 0x04c2, 0x30c4 }, - { 0x04c3, 0x30c6 }, - { 0x04c4, 0x30c8 }, - { 0x04c5, 0x30ca }, - { 0x04c6, 0x30cb }, - { 0x04c7, 0x30cc }, - { 0x04c8, 0x30cd }, - { 0x04c9, 0x30ce }, - { 0x04ca, 0x30cf }, - { 0x04cb, 0x30d2 }, - { 0x04cc, 0x30d5 }, - { 0x04cd, 0x30d8 }, - { 0x04ce, 0x30db }, - { 0x04cf, 0x30de }, - { 0x04d0, 0x30df }, - { 0x04d1, 0x30e0 }, - { 0x04d2, 0x30e1 }, - { 0x04d3, 0x30e2 }, - { 0x04d4, 0x30e4 }, - { 0x04d5, 0x30e6 }, - { 0x04d6, 0x30e8 }, - { 0x04d7, 0x30e9 }, - { 0x04d8, 0x30ea }, - { 0x04d9, 0x30eb }, - { 0x04da, 0x30ec }, - { 0x04db, 0x30ed }, - { 0x04dc, 0x30ef }, - { 0x04dd, 0x30f3 }, - { 0x04de, 0x309b }, - { 0x04df, 0x309c }, - { 0x05ac, 0x060c }, - { 0x05bb, 0x061b }, - { 0x05bf, 0x061f }, - { 0x05c1, 0x0621 }, - { 0x05c2, 0x0622 }, - { 0x05c3, 0x0623 }, - { 0x05c4, 0x0624 }, - { 0x05c5, 0x0625 }, - { 0x05c6, 0x0626 }, - { 0x05c7, 0x0627 }, - { 0x05c8, 0x0628 }, - { 0x05c9, 0x0629 }, - { 0x05ca, 0x062a }, - { 0x05cb, 0x062b }, - { 0x05cc, 0x062c }, - { 0x05cd, 0x062d }, - { 0x05ce, 0x062e }, - { 0x05cf, 0x062f }, - { 0x05d0, 0x0630 }, - { 0x05d1, 0x0631 }, - { 0x05d2, 0x0632 }, - { 0x05d3, 0x0633 }, - { 0x05d4, 0x0634 }, - { 0x05d5, 0x0635 }, - { 0x05d6, 0x0636 }, - { 0x05d7, 0x0637 }, - { 0x05d8, 0x0638 }, - { 0x05d9, 0x0639 }, - { 0x05da, 0x063a }, - { 0x05e0, 0x0640 }, - { 0x05e1, 0x0641 }, - { 0x05e2, 0x0642 }, - { 0x05e3, 0x0643 }, - { 0x05e4, 0x0644 }, - { 0x05e5, 0x0645 }, - { 0x05e6, 0x0646 }, - { 0x05e7, 0x0647 }, - { 0x05e8, 0x0648 }, - { 0x05e9, 0x0649 }, - { 0x05ea, 0x064a }, - { 0x05eb, 0x064b }, - { 0x05ec, 0x064c }, - { 0x05ed, 0x064d }, - { 0x05ee, 0x064e }, - { 0x05ef, 0x064f }, - { 0x05f0, 0x0650 }, - { 0x05f1, 0x0651 }, - { 0x05f2, 0x0652 }, - { 0x06a1, 0x0452 }, - { 0x06a2, 0x0453 }, - { 0x06a3, 0x0451 }, - { 0x06a4, 0x0454 }, - { 0x06a5, 0x0455 }, - { 0x06a6, 0x0456 }, - { 0x06a7, 0x0457 }, - { 0x06a8, 0x0458 }, - { 0x06a9, 0x0459 }, - { 0x06aa, 0x045a }, - { 0x06ab, 0x045b }, - { 0x06ac, 0x045c }, - { 0x06ae, 0x045e }, - { 0x06af, 0x045f }, - { 0x06b0, 0x2116 }, - { 0x06b1, 0x0402 }, - { 0x06b2, 0x0403 }, - { 0x06b3, 0x0401 }, - { 0x06b4, 0x0404 }, - { 0x06b5, 0x0405 }, - { 0x06b6, 0x0406 }, - { 0x06b7, 0x0407 }, - { 0x06b8, 0x0408 }, - { 0x06b9, 0x0409 }, - { 0x06ba, 0x040a }, - { 0x06bb, 0x040b }, - { 0x06bc, 0x040c }, - { 0x06be, 0x040e }, - { 0x06bf, 0x040f }, - { 0x06c0, 0x044e }, - { 0x06c1, 0x0430 }, - { 0x06c2, 0x0431 }, - { 0x06c3, 0x0446 }, - { 0x06c4, 0x0434 }, - { 0x06c5, 0x0435 }, - { 0x06c6, 0x0444 }, - { 0x06c7, 0x0433 }, - { 0x06c8, 0x0445 }, - { 0x06c9, 0x0438 }, - { 0x06ca, 0x0439 }, - { 0x06cb, 0x043a }, - { 0x06cc, 0x043b }, - { 0x06cd, 0x043c }, - { 0x06ce, 0x043d }, - { 0x06cf, 0x043e }, - { 0x06d0, 0x043f }, - { 0x06d1, 0x044f }, - { 0x06d2, 0x0440 }, - { 0x06d3, 0x0441 }, - { 0x06d4, 0x0442 }, - { 0x06d5, 0x0443 }, - { 0x06d6, 0x0436 }, - { 0x06d7, 0x0432 }, - { 0x06d8, 0x044c }, - { 0x06d9, 0x044b }, - { 0x06da, 0x0437 }, - { 0x06db, 0x0448 }, - { 0x06dc, 0x044d }, - { 0x06dd, 0x0449 }, - { 0x06de, 0x0447 }, - { 0x06df, 0x044a }, - { 0x06e0, 0x042e }, - { 0x06e1, 0x0410 }, - { 0x06e2, 0x0411 }, - { 0x06e3, 0x0426 }, - { 0x06e4, 0x0414 }, - { 0x06e5, 0x0415 }, - { 0x06e6, 0x0424 }, - { 0x06e7, 0x0413 }, - { 0x06e8, 0x0425 }, - { 0x06e9, 0x0418 }, - { 0x06ea, 0x0419 }, - { 0x06eb, 0x041a }, - { 0x06ec, 0x041b }, - { 0x06ed, 0x041c }, - { 0x06ee, 0x041d }, - { 0x06ef, 0x041e }, - { 0x06f0, 0x041f }, - { 0x06f1, 0x042f }, - { 0x06f2, 0x0420 }, - { 0x06f3, 0x0421 }, - { 0x06f4, 0x0422 }, - { 0x06f5, 0x0423 }, - { 0x06f6, 0x0416 }, - { 0x06f7, 0x0412 }, - { 0x06f8, 0x042c }, - { 0x06f9, 0x042b }, - { 0x06fa, 0x0417 }, - { 0x06fb, 0x0428 }, - { 0x06fc, 0x042d }, - { 0x06fd, 0x0429 }, - { 0x06fe, 0x0427 }, - { 0x06ff, 0x042a }, - { 0x07a1, 0x0386 }, - { 0x07a2, 0x0388 }, - { 0x07a3, 0x0389 }, - { 0x07a4, 0x038a }, - { 0x07a5, 0x03aa }, - { 0x07a7, 0x038c }, - { 0x07a8, 0x038e }, - { 0x07a9, 0x03ab }, - { 0x07ab, 0x038f }, - { 0x07ae, 0x0385 }, - { 0x07af, 0x2015 }, - { 0x07b1, 0x03ac }, - { 0x07b2, 0x03ad }, - { 0x07b3, 0x03ae }, - { 0x07b4, 0x03af }, - { 0x07b5, 0x03ca }, - { 0x07b6, 0x0390 }, - { 0x07b7, 0x03cc }, - { 0x07b8, 0x03cd }, - { 0x07b9, 0x03cb }, - { 0x07ba, 0x03b0 }, - { 0x07bb, 0x03ce }, - { 0x07c1, 0x0391 }, - { 0x07c2, 0x0392 }, - { 0x07c3, 0x0393 }, - { 0x07c4, 0x0394 }, - { 0x07c5, 0x0395 }, - { 0x07c6, 0x0396 }, - { 0x07c7, 0x0397 }, - { 0x07c8, 0x0398 }, - { 0x07c9, 0x0399 }, - { 0x07ca, 0x039a }, - { 0x07cb, 0x039b }, - { 0x07cc, 0x039c }, - { 0x07cd, 0x039d }, - { 0x07ce, 0x039e }, - { 0x07cf, 0x039f }, - { 0x07d0, 0x03a0 }, - { 0x07d1, 0x03a1 }, - { 0x07d2, 0x03a3 }, - { 0x07d4, 0x03a4 }, - { 0x07d5, 0x03a5 }, - { 0x07d6, 0x03a6 }, - { 0x07d7, 0x03a7 }, - { 0x07d8, 0x03a8 }, - { 0x07d9, 0x03a9 }, - { 0x07e1, 0x03b1 }, - { 0x07e2, 0x03b2 }, - { 0x07e3, 0x03b3 }, - { 0x07e4, 0x03b4 }, - { 0x07e5, 0x03b5 }, - { 0x07e6, 0x03b6 }, - { 0x07e7, 0x03b7 }, - { 0x07e8, 0x03b8 }, - { 0x07e9, 0x03b9 }, - { 0x07ea, 0x03ba }, - { 0x07eb, 0x03bb }, - { 0x07ec, 0x03bc }, - { 0x07ed, 0x03bd }, - { 0x07ee, 0x03be }, - { 0x07ef, 0x03bf }, - { 0x07f0, 0x03c0 }, - { 0x07f1, 0x03c1 }, - { 0x07f2, 0x03c3 }, - { 0x07f3, 0x03c2 }, - { 0x07f4, 0x03c4 }, - { 0x07f5, 0x03c5 }, - { 0x07f6, 0x03c6 }, - { 0x07f7, 0x03c7 }, - { 0x07f8, 0x03c8 }, - { 0x07f9, 0x03c9 }, - { 0x08a1, 0x23b7 }, - { 0x08a2, 0x250c }, - { 0x08a3, 0x2500 }, - { 0x08a4, 0x2320 }, - { 0x08a5, 0x2321 }, - { 0x08a6, 0x2502 }, - { 0x08a7, 0x23a1 }, - { 0x08a8, 0x23a3 }, - { 0x08a9, 0x23a4 }, - { 0x08aa, 0x23a6 }, - { 0x08ab, 0x239b }, - { 0x08ac, 0x239d }, - { 0x08ad, 0x239e }, - { 0x08ae, 0x23a0 }, - { 0x08af, 0x23a8 }, - { 0x08b0, 0x23ac }, - { 0x08bc, 0x2264 }, - { 0x08bd, 0x2260 }, - { 0x08be, 0x2265 }, - { 0x08bf, 0x222b }, - { 0x08c0, 0x2234 }, - { 0x08c1, 0x221d }, - { 0x08c2, 0x221e }, - { 0x08c5, 0x2207 }, - { 0x08c8, 0x223c }, - { 0x08c9, 0x2243 }, - { 0x08cd, 0x21d4 }, - { 0x08ce, 0x21d2 }, - { 0x08cf, 0x2261 }, - { 0x08d6, 0x221a }, - { 0x08da, 0x2282 }, - { 0x08db, 0x2283 }, - { 0x08dc, 0x2229 }, - { 0x08dd, 0x222a }, - { 0x08de, 0x2227 }, - { 0x08df, 0x2228 }, - { 0x08ef, 0x2202 }, - { 0x08f6, 0x0192 }, - { 0x08fb, 0x2190 }, - { 0x08fc, 0x2191 }, - { 0x08fd, 0x2192 }, - { 0x08fe, 0x2193 }, - { 0x09e0, 0x25c6 }, - { 0x09e1, 0x2592 }, - { 0x09e2, 0x2409 }, - { 0x09e3, 0x240c }, - { 0x09e4, 0x240d }, - { 0x09e5, 0x240a }, - { 0x09e8, 0x2424 }, - { 0x09e9, 0x240b }, - { 0x09ea, 0x2518 }, - { 0x09eb, 0x2510 }, - { 0x09ec, 0x250c }, - { 0x09ed, 0x2514 }, - { 0x09ee, 0x253c }, - { 0x09ef, 0x23ba }, - { 0x09f0, 0x23bb }, - { 0x09f1, 0x2500 }, - { 0x09f2, 0x23bc }, - { 0x09f3, 0x23bd }, - { 0x09f4, 0x251c }, - { 0x09f5, 0x2524 }, - { 0x09f6, 0x2534 }, - { 0x09f7, 0x252c }, - { 0x09f8, 0x2502 }, - { 0x0aa1, 0x2003 }, - { 0x0aa2, 0x2002 }, - { 0x0aa3, 0x2004 }, - { 0x0aa4, 0x2005 }, - { 0x0aa5, 0x2007 }, - { 0x0aa6, 0x2008 }, - { 0x0aa7, 0x2009 }, - { 0x0aa8, 0x200a }, - { 0x0aa9, 0x2014 }, - { 0x0aaa, 0x2013 }, - { 0x0aae, 0x2026 }, - { 0x0aaf, 0x2025 }, - { 0x0ab0, 0x2153 }, - { 0x0ab1, 0x2154 }, - { 0x0ab2, 0x2155 }, - { 0x0ab3, 0x2156 }, - { 0x0ab4, 0x2157 }, - { 0x0ab5, 0x2158 }, - { 0x0ab6, 0x2159 }, - { 0x0ab7, 0x215a }, - { 0x0ab8, 0x2105 }, - { 0x0abb, 0x2012 }, - { 0x0abc, 0x2329 }, - { 0x0abe, 0x232a }, - { 0x0ac3, 0x215b }, - { 0x0ac4, 0x215c }, - { 0x0ac5, 0x215d }, - { 0x0ac6, 0x215e }, - { 0x0ac9, 0x2122 }, - { 0x0aca, 0x2613 }, - { 0x0acc, 0x25c1 }, - { 0x0acd, 0x25b7 }, - { 0x0ace, 0x25cb }, - { 0x0acf, 0x25af }, - { 0x0ad0, 0x2018 }, - { 0x0ad1, 0x2019 }, - { 0x0ad2, 0x201c }, - { 0x0ad3, 0x201d }, - { 0x0ad4, 0x211e }, - { 0x0ad6, 0x2032 }, - { 0x0ad7, 0x2033 }, - { 0x0ad9, 0x271d }, - { 0x0adb, 0x25ac }, - { 0x0adc, 0x25c0 }, - { 0x0add, 0x25b6 }, - { 0x0ade, 0x25cf }, - { 0x0adf, 0x25ae }, - { 0x0ae0, 0x25e6 }, - { 0x0ae1, 0x25ab }, - { 0x0ae2, 0x25ad }, - { 0x0ae3, 0x25b3 }, - { 0x0ae4, 0x25bd }, - { 0x0ae5, 0x2606 }, - { 0x0ae6, 0x2022 }, - { 0x0ae7, 0x25aa }, - { 0x0ae8, 0x25b2 }, - { 0x0ae9, 0x25bc }, - { 0x0aea, 0x261c }, - { 0x0aeb, 0x261e }, - { 0x0aec, 0x2663 }, - { 0x0aed, 0x2666 }, - { 0x0aee, 0x2665 }, - { 0x0af0, 0x2720 }, - { 0x0af1, 0x2020 }, - { 0x0af2, 0x2021 }, - { 0x0af3, 0x2713 }, - { 0x0af4, 0x2717 }, - { 0x0af5, 0x266f }, - { 0x0af6, 0x266d }, - { 0x0af7, 0x2642 }, - { 0x0af8, 0x2640 }, - { 0x0af9, 0x260e }, - { 0x0afa, 0x2315 }, - { 0x0afb, 0x2117 }, - { 0x0afc, 0x2038 }, - { 0x0afd, 0x201a }, - { 0x0afe, 0x201e }, - { 0x0ba3, 0x003c }, - { 0x0ba6, 0x003e }, - { 0x0ba8, 0x2228 }, - { 0x0ba9, 0x2227 }, - { 0x0bc0, 0x00af }, - { 0x0bc2, 0x22a5 }, - { 0x0bc3, 0x2229 }, - { 0x0bc4, 0x230a }, - { 0x0bc6, 0x005f }, - { 0x0bca, 0x2218 }, - { 0x0bcc, 0x2395 }, - { 0x0bce, 0x22a4 }, - { 0x0bcf, 0x25cb }, - { 0x0bd3, 0x2308 }, - { 0x0bd6, 0x222a }, - { 0x0bd8, 0x2283 }, - { 0x0bda, 0x2282 }, - { 0x0bdc, 0x22a2 }, - { 0x0bfc, 0x22a3 }, - { 0x0cdf, 0x2017 }, - { 0x0ce0, 0x05d0 }, - { 0x0ce1, 0x05d1 }, - { 0x0ce2, 0x05d2 }, - { 0x0ce3, 0x05d3 }, - { 0x0ce4, 0x05d4 }, - { 0x0ce5, 0x05d5 }, - { 0x0ce6, 0x05d6 }, - { 0x0ce7, 0x05d7 }, - { 0x0ce8, 0x05d8 }, - { 0x0ce9, 0x05d9 }, - { 0x0cea, 0x05da }, - { 0x0ceb, 0x05db }, - { 0x0cec, 0x05dc }, - { 0x0ced, 0x05dd }, - { 0x0cee, 0x05de }, - { 0x0cef, 0x05df }, - { 0x0cf0, 0x05e0 }, - { 0x0cf1, 0x05e1 }, - { 0x0cf2, 0x05e2 }, - { 0x0cf3, 0x05e3 }, - { 0x0cf4, 0x05e4 }, - { 0x0cf5, 0x05e5 }, - { 0x0cf6, 0x05e6 }, - { 0x0cf7, 0x05e7 }, - { 0x0cf8, 0x05e8 }, - { 0x0cf9, 0x05e9 }, - { 0x0cfa, 0x05ea }, - { 0x0da1, 0x0e01 }, - { 0x0da2, 0x0e02 }, - { 0x0da3, 0x0e03 }, - { 0x0da4, 0x0e04 }, - { 0x0da5, 0x0e05 }, - { 0x0da6, 0x0e06 }, - { 0x0da7, 0x0e07 }, - { 0x0da8, 0x0e08 }, - { 0x0da9, 0x0e09 }, - { 0x0daa, 0x0e0a }, - { 0x0dab, 0x0e0b }, - { 0x0dac, 0x0e0c }, - { 0x0dad, 0x0e0d }, - { 0x0dae, 0x0e0e }, - { 0x0daf, 0x0e0f }, - { 0x0db0, 0x0e10 }, - { 0x0db1, 0x0e11 }, - { 0x0db2, 0x0e12 }, - { 0x0db3, 0x0e13 }, - { 0x0db4, 0x0e14 }, - { 0x0db5, 0x0e15 }, - { 0x0db6, 0x0e16 }, - { 0x0db7, 0x0e17 }, - { 0x0db8, 0x0e18 }, - { 0x0db9, 0x0e19 }, - { 0x0dba, 0x0e1a }, - { 0x0dbb, 0x0e1b }, - { 0x0dbc, 0x0e1c }, - { 0x0dbd, 0x0e1d }, - { 0x0dbe, 0x0e1e }, - { 0x0dbf, 0x0e1f }, - { 0x0dc0, 0x0e20 }, - { 0x0dc1, 0x0e21 }, - { 0x0dc2, 0x0e22 }, - { 0x0dc3, 0x0e23 }, - { 0x0dc4, 0x0e24 }, - { 0x0dc5, 0x0e25 }, - { 0x0dc6, 0x0e26 }, - { 0x0dc7, 0x0e27 }, - { 0x0dc8, 0x0e28 }, - { 0x0dc9, 0x0e29 }, - { 0x0dca, 0x0e2a }, - { 0x0dcb, 0x0e2b }, - { 0x0dcc, 0x0e2c }, - { 0x0dcd, 0x0e2d }, - { 0x0dce, 0x0e2e }, - { 0x0dcf, 0x0e2f }, - { 0x0dd0, 0x0e30 }, - { 0x0dd1, 0x0e31 }, - { 0x0dd2, 0x0e32 }, - { 0x0dd3, 0x0e33 }, - { 0x0dd4, 0x0e34 }, - { 0x0dd5, 0x0e35 }, - { 0x0dd6, 0x0e36 }, - { 0x0dd7, 0x0e37 }, - { 0x0dd8, 0x0e38 }, - { 0x0dd9, 0x0e39 }, - { 0x0dda, 0x0e3a }, - { 0x0ddf, 0x0e3f }, - { 0x0de0, 0x0e40 }, - { 0x0de1, 0x0e41 }, - { 0x0de2, 0x0e42 }, - { 0x0de3, 0x0e43 }, - { 0x0de4, 0x0e44 }, - { 0x0de5, 0x0e45 }, - { 0x0de6, 0x0e46 }, - { 0x0de7, 0x0e47 }, - { 0x0de8, 0x0e48 }, - { 0x0de9, 0x0e49 }, - { 0x0dea, 0x0e4a }, - { 0x0deb, 0x0e4b }, - { 0x0dec, 0x0e4c }, - { 0x0ded, 0x0e4d }, - { 0x0df0, 0x0e50 }, - { 0x0df1, 0x0e51 }, - { 0x0df2, 0x0e52 }, - { 0x0df3, 0x0e53 }, - { 0x0df4, 0x0e54 }, - { 0x0df5, 0x0e55 }, - { 0x0df6, 0x0e56 }, - { 0x0df7, 0x0e57 }, - { 0x0df8, 0x0e58 }, - { 0x0df9, 0x0e59 }, - { 0x0ea1, 0x3131 }, - { 0x0ea2, 0x3132 }, - { 0x0ea3, 0x3133 }, - { 0x0ea4, 0x3134 }, - { 0x0ea5, 0x3135 }, - { 0x0ea6, 0x3136 }, - { 0x0ea7, 0x3137 }, - { 0x0ea8, 0x3138 }, - { 0x0ea9, 0x3139 }, - { 0x0eaa, 0x313a }, - { 0x0eab, 0x313b }, - { 0x0eac, 0x313c }, - { 0x0ead, 0x313d }, - { 0x0eae, 0x313e }, - { 0x0eaf, 0x313f }, - { 0x0eb0, 0x3140 }, - { 0x0eb1, 0x3141 }, - { 0x0eb2, 0x3142 }, - { 0x0eb3, 0x3143 }, - { 0x0eb4, 0x3144 }, - { 0x0eb5, 0x3145 }, - { 0x0eb6, 0x3146 }, - { 0x0eb7, 0x3147 }, - { 0x0eb8, 0x3148 }, - { 0x0eb9, 0x3149 }, - { 0x0eba, 0x314a }, - { 0x0ebb, 0x314b }, - { 0x0ebc, 0x314c }, - { 0x0ebd, 0x314d }, - { 0x0ebe, 0x314e }, - { 0x0ebf, 0x314f }, - { 0x0ec0, 0x3150 }, - { 0x0ec1, 0x3151 }, - { 0x0ec2, 0x3152 }, - { 0x0ec3, 0x3153 }, - { 0x0ec4, 0x3154 }, - { 0x0ec5, 0x3155 }, - { 0x0ec6, 0x3156 }, - { 0x0ec7, 0x3157 }, - { 0x0ec8, 0x3158 }, - { 0x0ec9, 0x3159 }, - { 0x0eca, 0x315a }, - { 0x0ecb, 0x315b }, - { 0x0ecc, 0x315c }, - { 0x0ecd, 0x315d }, - { 0x0ece, 0x315e }, - { 0x0ecf, 0x315f }, - { 0x0ed0, 0x3160 }, - { 0x0ed1, 0x3161 }, - { 0x0ed2, 0x3162 }, - { 0x0ed3, 0x3163 }, - { 0x0ed4, 0x11a8 }, - { 0x0ed5, 0x11a9 }, - { 0x0ed6, 0x11aa }, - { 0x0ed7, 0x11ab }, - { 0x0ed8, 0x11ac }, - { 0x0ed9, 0x11ad }, - { 0x0eda, 0x11ae }, - { 0x0edb, 0x11af }, - { 0x0edc, 0x11b0 }, - { 0x0edd, 0x11b1 }, - { 0x0ede, 0x11b2 }, - { 0x0edf, 0x11b3 }, - { 0x0ee0, 0x11b4 }, - { 0x0ee1, 0x11b5 }, - { 0x0ee2, 0x11b6 }, - { 0x0ee3, 0x11b7 }, - { 0x0ee4, 0x11b8 }, - { 0x0ee5, 0x11b9 }, - { 0x0ee6, 0x11ba }, - { 0x0ee7, 0x11bb }, - { 0x0ee8, 0x11bc }, - { 0x0ee9, 0x11bd }, - { 0x0eea, 0x11be }, - { 0x0eeb, 0x11bf }, - { 0x0eec, 0x11c0 }, - { 0x0eed, 0x11c1 }, - { 0x0eee, 0x11c2 }, - { 0x0eef, 0x316d }, - { 0x0ef0, 0x3171 }, - { 0x0ef1, 0x3178 }, - { 0x0ef2, 0x317f }, - { 0x0ef3, 0x3181 }, - { 0x0ef4, 0x3184 }, - { 0x0ef5, 0x3186 }, - { 0x0ef6, 0x318d }, - { 0x0ef7, 0x318e }, - { 0x0ef8, 0x11eb }, - { 0x0ef9, 0x11f0 }, - { 0x0efa, 0x11f9 }, - { 0x0eff, 0x20a9 }, - { 0x13a4, 0x20ac }, - { 0x13bc, 0x0152 }, - { 0x13bd, 0x0153 }, - { 0x13be, 0x0178 }, - { 0x20ac, 0x20ac }, - { 0xfe50, '`' }, - { 0xfe51, 0x00b4 }, - { 0xfe52, '^' }, - { 0xfe53, '~' }, - { 0xfe54, 0x00af }, - { 0xfe55, 0x02d8 }, - { 0xfe56, 0x02d9 }, - { 0xfe57, 0x00a8 }, - { 0xfe58, 0x02da }, - { 0xfe59, 0x02dd }, - { 0xfe5a, 0x02c7 }, - { 0xfe5b, 0x00b8 }, - { 0xfe5c, 0x02db }, - { 0xfe5d, 0x037a }, - { 0xfe5e, 0x309b }, - { 0xfe5f, 0x309c }, - { 0xfe63, '/' }, - { 0xfe64, 0x02bc }, - { 0xfe65, 0x02bd }, - { 0xfe66, 0x02f5 }, - { 0xfe67, 0x02f3 }, - { 0xfe68, 0x02cd }, - { 0xfe69, 0xa788 }, - { 0xfe6a, 0x02f7 }, - { 0xfe6e, ',' }, - { 0xfe6f, 0x00a4 }, - { 0xfe80, 'a' }, /* XK_dead_a */ - { 0xfe81, 'A' }, /* XK_dead_A */ - { 0xfe82, 'e' }, /* XK_dead_e */ - { 0xfe83, 'E' }, /* XK_dead_E */ - { 0xfe84, 'i' }, /* XK_dead_i */ - { 0xfe85, 'I' }, /* XK_dead_I */ - { 0xfe86, 'o' }, /* XK_dead_o */ - { 0xfe87, 'O' }, /* XK_dead_O */ - { 0xfe88, 'u' }, /* XK_dead_u */ - { 0xfe89, 'U' }, /* XK_dead_U */ - { 0xfe8a, 0x0259 }, - { 0xfe8b, 0x018f }, - { 0xfe8c, 0x00b5 }, - { 0xfe90, '_' }, - { 0xfe91, 0x02c8 }, - { 0xfe92, 0x02cc }, - { 0xff80 /*XKB_KEY_KP_Space*/, ' ' }, - { 0xff95 /*XKB_KEY_KP_7*/, 0x0037 }, - { 0xff96 /*XKB_KEY_KP_4*/, 0x0034 }, - { 0xff97 /*XKB_KEY_KP_8*/, 0x0038 }, - { 0xff98 /*XKB_KEY_KP_6*/, 0x0036 }, - { 0xff99 /*XKB_KEY_KP_2*/, 0x0032 }, - { 0xff9a /*XKB_KEY_KP_9*/, 0x0039 }, - { 0xff9b /*XKB_KEY_KP_3*/, 0x0033 }, - { 0xff9c /*XKB_KEY_KP_1*/, 0x0031 }, - { 0xff9d /*XKB_KEY_KP_5*/, 0x0035 }, - { 0xff9e /*XKB_KEY_KP_0*/, 0x0030 }, - { 0xffaa /*XKB_KEY_KP_Multiply*/, '*' }, - { 0xffab /*XKB_KEY_KP_Add*/, '+' }, - { 0xffac /*XKB_KEY_KP_Separator*/, ',' }, - { 0xffad /*XKB_KEY_KP_Subtract*/, '-' }, - { 0xffae /*XKB_KEY_KP_Decimal*/, '.' }, - { 0xffaf /*XKB_KEY_KP_Divide*/, '/' }, - { 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 }, - { 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 }, - { 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 }, - { 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 }, - { 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 }, - { 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 }, - { 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 }, - { 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 }, - { 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 }, - { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 }, - { 0xffbd /*XKB_KEY_KP_Equal*/, '=' } -}; - -_SOKOL_PRIVATE int _sapp_x11_error_handler(Display* display, XErrorEvent* event) { - _SOKOL_UNUSED(display); - _sapp.x11.error_code = event->error_code; - return 0; -} - -_SOKOL_PRIVATE void _sapp_x11_grab_error_handler(void) { - _sapp.x11.error_code = Success; - XSetErrorHandler(_sapp_x11_error_handler); -} - -_SOKOL_PRIVATE void _sapp_x11_release_error_handler(void) { - XSync(_sapp.x11.display, False); - XSetErrorHandler(NULL); -} - -_SOKOL_PRIVATE void _sapp_x11_init_extensions(void) { - _sapp.x11.UTF8_STRING = XInternAtom(_sapp.x11.display, "UTF8_STRING", False); - _sapp.x11.WM_PROTOCOLS = XInternAtom(_sapp.x11.display, "WM_PROTOCOLS", False); - _sapp.x11.WM_DELETE_WINDOW = XInternAtom(_sapp.x11.display, "WM_DELETE_WINDOW", False); - _sapp.x11.WM_STATE = XInternAtom(_sapp.x11.display, "WM_STATE", False); - _sapp.x11.NET_WM_NAME = XInternAtom(_sapp.x11.display, "_NET_WM_NAME", False); - _sapp.x11.NET_WM_ICON_NAME = XInternAtom(_sapp.x11.display, "_NET_WM_ICON_NAME", False); - _sapp.x11.NET_WM_ICON = XInternAtom(_sapp.x11.display, "_NET_WM_ICON", False); - _sapp.x11.NET_WM_STATE = XInternAtom(_sapp.x11.display, "_NET_WM_STATE", False); - _sapp.x11.NET_WM_STATE_FULLSCREEN = XInternAtom(_sapp.x11.display, "_NET_WM_STATE_FULLSCREEN", False); - if (_sapp.drop.enabled) { - _sapp.x11.xdnd.XdndAware = XInternAtom(_sapp.x11.display, "XdndAware", False); - _sapp.x11.xdnd.XdndEnter = XInternAtom(_sapp.x11.display, "XdndEnter", False); - _sapp.x11.xdnd.XdndPosition = XInternAtom(_sapp.x11.display, "XdndPosition", False); - _sapp.x11.xdnd.XdndStatus = XInternAtom(_sapp.x11.display, "XdndStatus", False); - _sapp.x11.xdnd.XdndActionCopy = XInternAtom(_sapp.x11.display, "XdndActionCopy", False); - _sapp.x11.xdnd.XdndDrop = XInternAtom(_sapp.x11.display, "XdndDrop", False); - _sapp.x11.xdnd.XdndFinished = XInternAtom(_sapp.x11.display, "XdndFinished", False); - _sapp.x11.xdnd.XdndSelection = XInternAtom(_sapp.x11.display, "XdndSelection", False); - _sapp.x11.xdnd.XdndTypeList = XInternAtom(_sapp.x11.display, "XdndTypeList", False); - _sapp.x11.xdnd.text_uri_list = XInternAtom(_sapp.x11.display, "text/uri-list", False); - } - - /* check Xi extension for raw mouse input */ - if (XQueryExtension(_sapp.x11.display, "XInputExtension", &_sapp.x11.xi.major_opcode, &_sapp.x11.xi.event_base, &_sapp.x11.xi.error_base)) { - _sapp.x11.xi.major = 2; - _sapp.x11.xi.minor = 0; - if (XIQueryVersion(_sapp.x11.display, &_sapp.x11.xi.major, &_sapp.x11.xi.minor) == Success) { - _sapp.x11.xi.available = true; - } - } -} - -// translate the X11 KeySyms for a key to sokol-app key code -// NOTE: this is only used as a fallback, in case the XBK method fails -// it is layout-dependent and will fail partially on most non-US layouts. -// -_SOKOL_PRIVATE sapp_keycode _sapp_x11_translate_keysyms(const KeySym* keysyms, int width) { - if (width > 1) { - switch (keysyms[1]) { - case XK_KP_0: return SAPP_KEYCODE_KP_0; - case XK_KP_1: return SAPP_KEYCODE_KP_1; - case XK_KP_2: return SAPP_KEYCODE_KP_2; - case XK_KP_3: return SAPP_KEYCODE_KP_3; - case XK_KP_4: return SAPP_KEYCODE_KP_4; - case XK_KP_5: return SAPP_KEYCODE_KP_5; - case XK_KP_6: return SAPP_KEYCODE_KP_6; - case XK_KP_7: return SAPP_KEYCODE_KP_7; - case XK_KP_8: return SAPP_KEYCODE_KP_8; - case XK_KP_9: return SAPP_KEYCODE_KP_9; - case XK_KP_Separator: - case XK_KP_Decimal: return SAPP_KEYCODE_KP_DECIMAL; - case XK_KP_Equal: return SAPP_KEYCODE_KP_EQUAL; - case XK_KP_Enter: return SAPP_KEYCODE_KP_ENTER; - default: break; - } - } - - switch (keysyms[0]) { - case XK_Escape: return SAPP_KEYCODE_ESCAPE; - case XK_Tab: return SAPP_KEYCODE_TAB; - case XK_Shift_L: return SAPP_KEYCODE_LEFT_SHIFT; - case XK_Shift_R: return SAPP_KEYCODE_RIGHT_SHIFT; - case XK_Control_L: return SAPP_KEYCODE_LEFT_CONTROL; - case XK_Control_R: return SAPP_KEYCODE_RIGHT_CONTROL; - case XK_Meta_L: - case XK_Alt_L: return SAPP_KEYCODE_LEFT_ALT; - case XK_Mode_switch: // Mapped to Alt_R on many keyboards - case XK_ISO_Level3_Shift: // AltGr on at least some machines - case XK_Meta_R: - case XK_Alt_R: return SAPP_KEYCODE_RIGHT_ALT; - case XK_Super_L: return SAPP_KEYCODE_LEFT_SUPER; - case XK_Super_R: return SAPP_KEYCODE_RIGHT_SUPER; - case XK_Menu: return SAPP_KEYCODE_MENU; - case XK_Num_Lock: return SAPP_KEYCODE_NUM_LOCK; - case XK_Caps_Lock: return SAPP_KEYCODE_CAPS_LOCK; - case XK_Print: return SAPP_KEYCODE_PRINT_SCREEN; - case XK_Scroll_Lock: return SAPP_KEYCODE_SCROLL_LOCK; - case XK_Pause: return SAPP_KEYCODE_PAUSE; - case XK_Delete: return SAPP_KEYCODE_DELETE; - case XK_BackSpace: return SAPP_KEYCODE_BACKSPACE; - case XK_Return: return SAPP_KEYCODE_ENTER; - case XK_Home: return SAPP_KEYCODE_HOME; - case XK_End: return SAPP_KEYCODE_END; - case XK_Page_Up: return SAPP_KEYCODE_PAGE_UP; - case XK_Page_Down: return SAPP_KEYCODE_PAGE_DOWN; - case XK_Insert: return SAPP_KEYCODE_INSERT; - case XK_Left: return SAPP_KEYCODE_LEFT; - case XK_Right: return SAPP_KEYCODE_RIGHT; - case XK_Down: return SAPP_KEYCODE_DOWN; - case XK_Up: return SAPP_KEYCODE_UP; - case XK_F1: return SAPP_KEYCODE_F1; - case XK_F2: return SAPP_KEYCODE_F2; - case XK_F3: return SAPP_KEYCODE_F3; - case XK_F4: return SAPP_KEYCODE_F4; - case XK_F5: return SAPP_KEYCODE_F5; - case XK_F6: return SAPP_KEYCODE_F6; - case XK_F7: return SAPP_KEYCODE_F7; - case XK_F8: return SAPP_KEYCODE_F8; - case XK_F9: return SAPP_KEYCODE_F9; - case XK_F10: return SAPP_KEYCODE_F10; - case XK_F11: return SAPP_KEYCODE_F11; - case XK_F12: return SAPP_KEYCODE_F12; - case XK_F13: return SAPP_KEYCODE_F13; - case XK_F14: return SAPP_KEYCODE_F14; - case XK_F15: return SAPP_KEYCODE_F15; - case XK_F16: return SAPP_KEYCODE_F16; - case XK_F17: return SAPP_KEYCODE_F17; - case XK_F18: return SAPP_KEYCODE_F18; - case XK_F19: return SAPP_KEYCODE_F19; - case XK_F20: return SAPP_KEYCODE_F20; - case XK_F21: return SAPP_KEYCODE_F21; - case XK_F22: return SAPP_KEYCODE_F22; - case XK_F23: return SAPP_KEYCODE_F23; - case XK_F24: return SAPP_KEYCODE_F24; - case XK_F25: return SAPP_KEYCODE_F25; - - // numeric keypad - case XK_KP_Divide: return SAPP_KEYCODE_KP_DIVIDE; - case XK_KP_Multiply: return SAPP_KEYCODE_KP_MULTIPLY; - case XK_KP_Subtract: return SAPP_KEYCODE_KP_SUBTRACT; - case XK_KP_Add: return SAPP_KEYCODE_KP_ADD; - - // these should have been detected in secondary keysym test above! - case XK_KP_Insert: return SAPP_KEYCODE_KP_0; - case XK_KP_End: return SAPP_KEYCODE_KP_1; - case XK_KP_Down: return SAPP_KEYCODE_KP_2; - case XK_KP_Page_Down: return SAPP_KEYCODE_KP_3; - case XK_KP_Left: return SAPP_KEYCODE_KP_4; - case XK_KP_Right: return SAPP_KEYCODE_KP_6; - case XK_KP_Home: return SAPP_KEYCODE_KP_7; - case XK_KP_Up: return SAPP_KEYCODE_KP_8; - case XK_KP_Page_Up: return SAPP_KEYCODE_KP_9; - case XK_KP_Delete: return SAPP_KEYCODE_KP_DECIMAL; - case XK_KP_Equal: return SAPP_KEYCODE_KP_EQUAL; - case XK_KP_Enter: return SAPP_KEYCODE_KP_ENTER; - - // last resort: Check for printable keys (should not happen if the XKB - // extension is available). This will give a layout dependent mapping - // (which is wrong, and we may miss some keys, especially on non-US - // keyboards), but it's better than nothing... - case XK_a: return SAPP_KEYCODE_A; - case XK_b: return SAPP_KEYCODE_B; - case XK_c: return SAPP_KEYCODE_C; - case XK_d: return SAPP_KEYCODE_D; - case XK_e: return SAPP_KEYCODE_E; - case XK_f: return SAPP_KEYCODE_F; - case XK_g: return SAPP_KEYCODE_G; - case XK_h: return SAPP_KEYCODE_H; - case XK_i: return SAPP_KEYCODE_I; - case XK_j: return SAPP_KEYCODE_J; - case XK_k: return SAPP_KEYCODE_K; - case XK_l: return SAPP_KEYCODE_L; - case XK_m: return SAPP_KEYCODE_M; - case XK_n: return SAPP_KEYCODE_N; - case XK_o: return SAPP_KEYCODE_O; - case XK_p: return SAPP_KEYCODE_P; - case XK_q: return SAPP_KEYCODE_Q; - case XK_r: return SAPP_KEYCODE_R; - case XK_s: return SAPP_KEYCODE_S; - case XK_t: return SAPP_KEYCODE_T; - case XK_u: return SAPP_KEYCODE_U; - case XK_v: return SAPP_KEYCODE_V; - case XK_w: return SAPP_KEYCODE_W; - case XK_x: return SAPP_KEYCODE_X; - case XK_y: return SAPP_KEYCODE_Y; - case XK_z: return SAPP_KEYCODE_Z; - case XK_1: return SAPP_KEYCODE_1; - case XK_2: return SAPP_KEYCODE_2; - case XK_3: return SAPP_KEYCODE_3; - case XK_4: return SAPP_KEYCODE_4; - case XK_5: return SAPP_KEYCODE_5; - case XK_6: return SAPP_KEYCODE_6; - case XK_7: return SAPP_KEYCODE_7; - case XK_8: return SAPP_KEYCODE_8; - case XK_9: return SAPP_KEYCODE_9; - case XK_0: return SAPP_KEYCODE_0; - case XK_space: return SAPP_KEYCODE_SPACE; - case XK_minus: return SAPP_KEYCODE_MINUS; - case XK_equal: return SAPP_KEYCODE_EQUAL; - case XK_bracketleft: return SAPP_KEYCODE_LEFT_BRACKET; - case XK_bracketright: return SAPP_KEYCODE_RIGHT_BRACKET; - case XK_backslash: return SAPP_KEYCODE_BACKSLASH; - case XK_semicolon: return SAPP_KEYCODE_SEMICOLON; - case XK_apostrophe: return SAPP_KEYCODE_APOSTROPHE; - case XK_grave: return SAPP_KEYCODE_GRAVE_ACCENT; - case XK_comma: return SAPP_KEYCODE_COMMA; - case XK_period: return SAPP_KEYCODE_PERIOD; - case XK_slash: return SAPP_KEYCODE_SLASH; - case XK_less: return SAPP_KEYCODE_WORLD_1; // At least in some layouts... - default: break; - } - - // no matching translation was found - return SAPP_KEYCODE_INVALID; -} - - -// setup dynamic keycode/scancode mapping tables, this is required -// for getting layout-independent keycodes on X11. -// -// see GLFW x11_init.c/createKeyTables() -_SOKOL_PRIVATE void _sapp_x11_init_keytable(void) { - for (int i = 0; i < SAPP_MAX_KEYCODES; i++) { - _sapp.keycodes[i] = SAPP_KEYCODE_INVALID; - } - // use XKB to determine physical key locations independently of the current keyboard layout - XkbDescPtr desc = XkbGetMap(_sapp.x11.display, 0, XkbUseCoreKbd); - SOKOL_ASSERT(desc); - XkbGetNames(_sapp.x11.display, XkbKeyNamesMask | XkbKeyAliasesMask, desc); - - const int scancode_min = desc->min_key_code; - const int scancode_max = desc->max_key_code; - - const struct { sapp_keycode key; const char* name; } keymap[] = { - { SAPP_KEYCODE_GRAVE_ACCENT, "TLDE" }, - { SAPP_KEYCODE_1, "AE01" }, - { SAPP_KEYCODE_2, "AE02" }, - { SAPP_KEYCODE_3, "AE03" }, - { SAPP_KEYCODE_4, "AE04" }, - { SAPP_KEYCODE_5, "AE05" }, - { SAPP_KEYCODE_6, "AE06" }, - { SAPP_KEYCODE_7, "AE07" }, - { SAPP_KEYCODE_8, "AE08" }, - { SAPP_KEYCODE_9, "AE09" }, - { SAPP_KEYCODE_0, "AE10" }, - { SAPP_KEYCODE_MINUS, "AE11" }, - { SAPP_KEYCODE_EQUAL, "AE12" }, - { SAPP_KEYCODE_Q, "AD01" }, - { SAPP_KEYCODE_W, "AD02" }, - { SAPP_KEYCODE_E, "AD03" }, - { SAPP_KEYCODE_R, "AD04" }, - { SAPP_KEYCODE_T, "AD05" }, - { SAPP_KEYCODE_Y, "AD06" }, - { SAPP_KEYCODE_U, "AD07" }, - { SAPP_KEYCODE_I, "AD08" }, - { SAPP_KEYCODE_O, "AD09" }, - { SAPP_KEYCODE_P, "AD10" }, - { SAPP_KEYCODE_LEFT_BRACKET, "AD11" }, - { SAPP_KEYCODE_RIGHT_BRACKET, "AD12" }, - { SAPP_KEYCODE_A, "AC01" }, - { SAPP_KEYCODE_S, "AC02" }, - { SAPP_KEYCODE_D, "AC03" }, - { SAPP_KEYCODE_F, "AC04" }, - { SAPP_KEYCODE_G, "AC05" }, - { SAPP_KEYCODE_H, "AC06" }, - { SAPP_KEYCODE_J, "AC07" }, - { SAPP_KEYCODE_K, "AC08" }, - { SAPP_KEYCODE_L, "AC09" }, - { SAPP_KEYCODE_SEMICOLON, "AC10" }, - { SAPP_KEYCODE_APOSTROPHE, "AC11" }, - { SAPP_KEYCODE_Z, "AB01" }, - { SAPP_KEYCODE_X, "AB02" }, - { SAPP_KEYCODE_C, "AB03" }, - { SAPP_KEYCODE_V, "AB04" }, - { SAPP_KEYCODE_B, "AB05" }, - { SAPP_KEYCODE_N, "AB06" }, - { SAPP_KEYCODE_M, "AB07" }, - { SAPP_KEYCODE_COMMA, "AB08" }, - { SAPP_KEYCODE_PERIOD, "AB09" }, - { SAPP_KEYCODE_SLASH, "AB10" }, - { SAPP_KEYCODE_BACKSLASH, "BKSL" }, - { SAPP_KEYCODE_WORLD_1, "LSGT" }, - { SAPP_KEYCODE_SPACE, "SPCE" }, - { SAPP_KEYCODE_ESCAPE, "ESC" }, - { SAPP_KEYCODE_ENTER, "RTRN" }, - { SAPP_KEYCODE_TAB, "TAB" }, - { SAPP_KEYCODE_BACKSPACE, "BKSP" }, - { SAPP_KEYCODE_INSERT, "INS" }, - { SAPP_KEYCODE_DELETE, "DELE" }, - { SAPP_KEYCODE_RIGHT, "RGHT" }, - { SAPP_KEYCODE_LEFT, "LEFT" }, - { SAPP_KEYCODE_DOWN, "DOWN" }, - { SAPP_KEYCODE_UP, "UP" }, - { SAPP_KEYCODE_PAGE_UP, "PGUP" }, - { SAPP_KEYCODE_PAGE_DOWN, "PGDN" }, - { SAPP_KEYCODE_HOME, "HOME" }, - { SAPP_KEYCODE_END, "END" }, - { SAPP_KEYCODE_CAPS_LOCK, "CAPS" }, - { SAPP_KEYCODE_SCROLL_LOCK, "SCLK" }, - { SAPP_KEYCODE_NUM_LOCK, "NMLK" }, - { SAPP_KEYCODE_PRINT_SCREEN, "PRSC" }, - { SAPP_KEYCODE_PAUSE, "PAUS" }, - { SAPP_KEYCODE_F1, "FK01" }, - { SAPP_KEYCODE_F2, "FK02" }, - { SAPP_KEYCODE_F3, "FK03" }, - { SAPP_KEYCODE_F4, "FK04" }, - { SAPP_KEYCODE_F5, "FK05" }, - { SAPP_KEYCODE_F6, "FK06" }, - { SAPP_KEYCODE_F7, "FK07" }, - { SAPP_KEYCODE_F8, "FK08" }, - { SAPP_KEYCODE_F9, "FK09" }, - { SAPP_KEYCODE_F10, "FK10" }, - { SAPP_KEYCODE_F11, "FK11" }, - { SAPP_KEYCODE_F12, "FK12" }, - { SAPP_KEYCODE_F13, "FK13" }, - { SAPP_KEYCODE_F14, "FK14" }, - { SAPP_KEYCODE_F15, "FK15" }, - { SAPP_KEYCODE_F16, "FK16" }, - { SAPP_KEYCODE_F17, "FK17" }, - { SAPP_KEYCODE_F18, "FK18" }, - { SAPP_KEYCODE_F19, "FK19" }, - { SAPP_KEYCODE_F20, "FK20" }, - { SAPP_KEYCODE_F21, "FK21" }, - { SAPP_KEYCODE_F22, "FK22" }, - { SAPP_KEYCODE_F23, "FK23" }, - { SAPP_KEYCODE_F24, "FK24" }, - { SAPP_KEYCODE_F25, "FK25" }, - { SAPP_KEYCODE_KP_0, "KP0" }, - { SAPP_KEYCODE_KP_1, "KP1" }, - { SAPP_KEYCODE_KP_2, "KP2" }, - { SAPP_KEYCODE_KP_3, "KP3" }, - { SAPP_KEYCODE_KP_4, "KP4" }, - { SAPP_KEYCODE_KP_5, "KP5" }, - { SAPP_KEYCODE_KP_6, "KP6" }, - { SAPP_KEYCODE_KP_7, "KP7" }, - { SAPP_KEYCODE_KP_8, "KP8" }, - { SAPP_KEYCODE_KP_9, "KP9" }, - { SAPP_KEYCODE_KP_DECIMAL, "KPDL" }, - { SAPP_KEYCODE_KP_DIVIDE, "KPDV" }, - { SAPP_KEYCODE_KP_MULTIPLY, "KPMU" }, - { SAPP_KEYCODE_KP_SUBTRACT, "KPSU" }, - { SAPP_KEYCODE_KP_ADD, "KPAD" }, - { SAPP_KEYCODE_KP_ENTER, "KPEN" }, - { SAPP_KEYCODE_KP_EQUAL, "KPEQ" }, - { SAPP_KEYCODE_LEFT_SHIFT, "LFSH" }, - { SAPP_KEYCODE_LEFT_CONTROL, "LCTL" }, - { SAPP_KEYCODE_LEFT_ALT, "LALT" }, - { SAPP_KEYCODE_LEFT_SUPER, "LWIN" }, - { SAPP_KEYCODE_RIGHT_SHIFT, "RTSH" }, - { SAPP_KEYCODE_RIGHT_CONTROL, "RCTL" }, - { SAPP_KEYCODE_RIGHT_ALT, "RALT" }, - { SAPP_KEYCODE_RIGHT_ALT, "LVL3" }, - { SAPP_KEYCODE_RIGHT_ALT, "MDSW" }, - { SAPP_KEYCODE_RIGHT_SUPER, "RWIN" }, - { SAPP_KEYCODE_MENU, "MENU" } - }; - const int num_keymap_items = (int)(sizeof(keymap) / sizeof(keymap[0])); - - // find X11 keycode to sokol-app key code mapping - for (int scancode = scancode_min; scancode <= scancode_max; scancode++) { - sapp_keycode key = SAPP_KEYCODE_INVALID; - for (int i = 0; i < num_keymap_items; i++) { - if (strncmp(desc->names->keys[scancode].name, keymap[i].name, XkbKeyNameLength) == 0) { - key = keymap[i].key; - break; - } - } - - // fall back to key aliases in case the key name did not match - for (int i = 0; i < desc->names->num_key_aliases; i++) { - if (key != SAPP_KEYCODE_INVALID) { - break; - } - if (strncmp(desc->names->key_aliases[i].real, desc->names->keys[scancode].name, XkbKeyNameLength) != 0) { - continue; - } - for (int j = 0; j < num_keymap_items; j++) { - if (strncmp(desc->names->key_aliases[i].alias, keymap[i].name, XkbKeyNameLength) == 0) { - key = keymap[i].key; - break; - } - } - } - _sapp.keycodes[scancode] = key; - } - XkbFreeNames(desc, XkbKeyNamesMask, True); - XkbFreeKeyboard(desc, 0, True); - - int width = 0; - KeySym* keysyms = XGetKeyboardMapping(_sapp.x11.display, scancode_min, scancode_max - scancode_min + 1, &width); - for (int scancode = scancode_min; scancode <= scancode_max; scancode++) { - // translate untranslated key codes using the traditional X11 KeySym lookups - if (_sapp.keycodes[scancode] == SAPP_KEYCODE_INVALID) { - const size_t base = (size_t)((scancode - scancode_min) * width); - _sapp.keycodes[scancode] = _sapp_x11_translate_keysyms(&keysyms[base], width); - } - } - XFree(keysyms); -} - -_SOKOL_PRIVATE void _sapp_x11_query_system_dpi(void) { - /* from GLFW: - - NOTE: Default to the display-wide DPI as we don't currently have a policy - for which monitor a window is considered to be on - - _sapp.x11.dpi = DisplayWidth(_sapp.x11.display, _sapp.x11.screen) * - 25.4f / DisplayWidthMM(_sapp.x11.display, _sapp.x11.screen); - - NOTE: Basing the scale on Xft.dpi where available should provide the most - consistent user experience (matches Qt, Gtk, etc), although not - always the most accurate one - */ - bool dpi_ok = false; - char* rms = XResourceManagerString(_sapp.x11.display); - if (rms) { - XrmDatabase db = XrmGetStringDatabase(rms); - if (db) { - XrmValue value; - char* type = NULL; - if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) { - if (type && strcmp(type, "String") == 0) { - _sapp.x11.dpi = atof(value.addr); - dpi_ok = true; - } - } - XrmDestroyDatabase(db); - } - } - // fallback if querying DPI had failed: assume the standard DPI 96.0f - if (!dpi_ok) { - _sapp.x11.dpi = 96.0f; - _SAPP_WARN(LINUX_X11_QUERY_SYSTEM_DPI_FAILED); - } -} - -#if defined(_SAPP_GLX) - -_SOKOL_PRIVATE bool _sapp_glx_has_ext(const char* ext, const char* extensions) { - SOKOL_ASSERT(ext); - const char* start = extensions; - while (true) { - const char* where = strstr(start, ext); - if (!where) { - return false; - } - const char* terminator = where + strlen(ext); - if ((where == start) || (*(where - 1) == ' ')) { - if (*terminator == ' ' || *terminator == '\0') { - break; - } - } - start = terminator; - } - return true; -} - -_SOKOL_PRIVATE bool _sapp_glx_extsupported(const char* ext, const char* extensions) { - if (extensions) { - return _sapp_glx_has_ext(ext, extensions); - } - else { - return false; - } -} - -_SOKOL_PRIVATE void* _sapp_glx_getprocaddr(const char* procname) -{ - if (_sapp.glx.GetProcAddress) { - return (void*) _sapp.glx.GetProcAddress(procname); - } - else if (_sapp.glx.GetProcAddressARB) { - return (void*) _sapp.glx.GetProcAddressARB(procname); - } - else { - return dlsym(_sapp.glx.libgl, procname); - } -} - -_SOKOL_PRIVATE void _sapp_glx_init(void) { - const char* sonames[] = { "libGL.so.1", "libGL.so", 0 }; - for (int i = 0; sonames[i]; i++) { - _sapp.glx.libgl = dlopen(sonames[i], RTLD_LAZY|RTLD_GLOBAL); - if (_sapp.glx.libgl) { - break; - } - } - if (!_sapp.glx.libgl) { - _SAPP_PANIC(LINUX_GLX_LOAD_LIBGL_FAILED); - } - _sapp.glx.GetFBConfigs = (PFNGLXGETFBCONFIGSPROC) dlsym(_sapp.glx.libgl, "glXGetFBConfigs"); - _sapp.glx.GetFBConfigAttrib = (PFNGLXGETFBCONFIGATTRIBPROC) dlsym(_sapp.glx.libgl, "glXGetFBConfigAttrib"); - _sapp.glx.GetClientString = (PFNGLXGETCLIENTSTRINGPROC) dlsym(_sapp.glx.libgl, "glXGetClientString"); - _sapp.glx.QueryExtension = (PFNGLXQUERYEXTENSIONPROC) dlsym(_sapp.glx.libgl, "glXQueryExtension"); - _sapp.glx.QueryVersion = (PFNGLXQUERYVERSIONPROC) dlsym(_sapp.glx.libgl, "glXQueryVersion"); - _sapp.glx.DestroyContext = (PFNGLXDESTROYCONTEXTPROC) dlsym(_sapp.glx.libgl, "glXDestroyContext"); - _sapp.glx.MakeCurrent = (PFNGLXMAKECURRENTPROC) dlsym(_sapp.glx.libgl, "glXMakeCurrent"); - _sapp.glx.SwapBuffers = (PFNGLXSWAPBUFFERSPROC) dlsym(_sapp.glx.libgl, "glXSwapBuffers"); - _sapp.glx.QueryExtensionsString = (PFNGLXQUERYEXTENSIONSSTRINGPROC) dlsym(_sapp.glx.libgl, "glXQueryExtensionsString"); - _sapp.glx.CreateWindow = (PFNGLXCREATEWINDOWPROC) dlsym(_sapp.glx.libgl, "glXCreateWindow"); - _sapp.glx.DestroyWindow = (PFNGLXDESTROYWINDOWPROC) dlsym(_sapp.glx.libgl, "glXDestroyWindow"); - _sapp.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC) dlsym(_sapp.glx.libgl, "glXGetProcAddress"); - _sapp.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC) dlsym(_sapp.glx.libgl, "glXGetProcAddressARB"); - _sapp.glx.GetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) dlsym(_sapp.glx.libgl, "glXGetVisualFromFBConfig"); - if (!_sapp.glx.GetFBConfigs || - !_sapp.glx.GetFBConfigAttrib || - !_sapp.glx.GetClientString || - !_sapp.glx.QueryExtension || - !_sapp.glx.QueryVersion || - !_sapp.glx.DestroyContext || - !_sapp.glx.MakeCurrent || - !_sapp.glx.SwapBuffers || - !_sapp.glx.QueryExtensionsString || - !_sapp.glx.CreateWindow || - !_sapp.glx.DestroyWindow || - !_sapp.glx.GetProcAddress || - !_sapp.glx.GetProcAddressARB || - !_sapp.glx.GetVisualFromFBConfig) - { - _SAPP_PANIC(LINUX_GLX_LOAD_ENTRY_POINTS_FAILED); - } - - if (!_sapp.glx.QueryExtension(_sapp.x11.display, &_sapp.glx.error_base, &_sapp.glx.event_base)) { - _SAPP_PANIC(LINUX_GLX_EXTENSION_NOT_FOUND); - } - if (!_sapp.glx.QueryVersion(_sapp.x11.display, &_sapp.glx.major, &_sapp.glx.minor)) { - _SAPP_PANIC(LINUX_GLX_QUERY_VERSION_FAILED); - } - if (_sapp.glx.major == 1 && _sapp.glx.minor < 3) { - _SAPP_PANIC(LINUX_GLX_VERSION_TOO_LOW); - } - const char* exts = _sapp.glx.QueryExtensionsString(_sapp.x11.display, _sapp.x11.screen); - if (_sapp_glx_extsupported("GLX_EXT_swap_control", exts)) { - _sapp.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) _sapp_glx_getprocaddr("glXSwapIntervalEXT"); - _sapp.glx.EXT_swap_control = 0 != _sapp.glx.SwapIntervalEXT; - } - if (_sapp_glx_extsupported("GLX_MESA_swap_control", exts)) { - _sapp.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) _sapp_glx_getprocaddr("glXSwapIntervalMESA"); - _sapp.glx.MESA_swap_control = 0 != _sapp.glx.SwapIntervalMESA; - } - _sapp.glx.ARB_multisample = _sapp_glx_extsupported("GLX_ARB_multisample", exts); - if (_sapp_glx_extsupported("GLX_ARB_create_context", exts)) { - _sapp.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) _sapp_glx_getprocaddr("glXCreateContextAttribsARB"); - _sapp.glx.ARB_create_context = 0 != _sapp.glx.CreateContextAttribsARB; - } - _sapp.glx.ARB_create_context_profile = _sapp_glx_extsupported("GLX_ARB_create_context_profile", exts); -} - -_SOKOL_PRIVATE int _sapp_glx_attrib(GLXFBConfig fbconfig, int attrib) { - int value; - _sapp.glx.GetFBConfigAttrib(_sapp.x11.display, fbconfig, attrib, &value); - return value; -} - -_SOKOL_PRIVATE GLXFBConfig _sapp_glx_choosefbconfig(void) { - GLXFBConfig* native_configs; - _sapp_gl_fbconfig* usable_configs; - const _sapp_gl_fbconfig* closest; - int i, native_count, usable_count; - const char* vendor; - bool trust_window_bit = true; - - /* HACK: This is a (hopefully temporary) workaround for Chromium - (VirtualBox GL) not setting the window bit on any GLXFBConfigs - */ - vendor = _sapp.glx.GetClientString(_sapp.x11.display, GLX_VENDOR); - if (vendor && strcmp(vendor, "Chromium") == 0) { - trust_window_bit = false; - } - - native_configs = _sapp.glx.GetFBConfigs(_sapp.x11.display, _sapp.x11.screen, &native_count); - if (!native_configs || !native_count) { - _SAPP_PANIC(LINUX_GLX_NO_GLXFBCONFIGS); - } - - usable_configs = (_sapp_gl_fbconfig*) _sapp_malloc_clear((size_t)native_count * sizeof(_sapp_gl_fbconfig)); - usable_count = 0; - for (i = 0; i < native_count; i++) { - const GLXFBConfig n = native_configs[i]; - _sapp_gl_fbconfig* u = usable_configs + usable_count; - _sapp_gl_init_fbconfig(u); - - /* Only consider RGBA GLXFBConfigs */ - if (0 == (_sapp_glx_attrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) { - continue; - } - /* Only consider window GLXFBConfigs */ - if (0 == (_sapp_glx_attrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) { - if (trust_window_bit) { - continue; - } - } - u->red_bits = _sapp_glx_attrib(n, GLX_RED_SIZE); - u->green_bits = _sapp_glx_attrib(n, GLX_GREEN_SIZE); - u->blue_bits = _sapp_glx_attrib(n, GLX_BLUE_SIZE); - u->alpha_bits = _sapp_glx_attrib(n, GLX_ALPHA_SIZE); - u->depth_bits = _sapp_glx_attrib(n, GLX_DEPTH_SIZE); - u->stencil_bits = _sapp_glx_attrib(n, GLX_STENCIL_SIZE); - if (_sapp_glx_attrib(n, GLX_DOUBLEBUFFER)) { - u->doublebuffer = true; - } - if (_sapp.glx.ARB_multisample) { - u->samples = _sapp_glx_attrib(n, GLX_SAMPLES); - } - u->handle = (uintptr_t) n; - usable_count++; - } - _sapp_gl_fbconfig desired; - _sapp_gl_init_fbconfig(&desired); - desired.red_bits = 8; - desired.green_bits = 8; - desired.blue_bits = 8; - desired.alpha_bits = 8; - desired.depth_bits = 24; - desired.stencil_bits = 8; - desired.doublebuffer = true; - desired.samples = _sapp.sample_count > 1 ? _sapp.sample_count : 0; - closest = _sapp_gl_choose_fbconfig(&desired, usable_configs, usable_count); - GLXFBConfig result = 0; - if (closest) { - result = (GLXFBConfig) closest->handle; - } - XFree(native_configs); - _sapp_free(usable_configs); - return result; -} - -_SOKOL_PRIVATE void _sapp_glx_choose_visual(Visual** visual, int* depth) { - GLXFBConfig native = _sapp_glx_choosefbconfig(); - if (0 == native) { - _SAPP_PANIC(LINUX_GLX_NO_SUITABLE_GLXFBCONFIG); - } - XVisualInfo* result = _sapp.glx.GetVisualFromFBConfig(_sapp.x11.display, native); - if (!result) { - _SAPP_PANIC(LINUX_GLX_GET_VISUAL_FROM_FBCONFIG_FAILED); - } - *visual = result->visual; - *depth = result->depth; - XFree(result); -} - -_SOKOL_PRIVATE void _sapp_glx_make_current(void) { - _sapp.glx.MakeCurrent(_sapp.x11.display, _sapp.glx.window, _sapp.glx.ctx); - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); -} - -_SOKOL_PRIVATE void _sapp_glx_create_context(void) { - GLXFBConfig native = _sapp_glx_choosefbconfig(); - if (0 == native){ - _SAPP_PANIC(LINUX_GLX_NO_SUITABLE_GLXFBCONFIG); - } - if (!(_sapp.glx.ARB_create_context && _sapp.glx.ARB_create_context_profile)) { - _SAPP_PANIC(LINUX_GLX_REQUIRED_EXTENSIONS_MISSING); - } - _sapp_x11_grab_error_handler(); - const int attribs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, _sapp.desc.gl_major_version, - GLX_CONTEXT_MINOR_VERSION_ARB, _sapp.desc.gl_minor_version, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - 0, 0 - }; - _sapp.glx.ctx = _sapp.glx.CreateContextAttribsARB(_sapp.x11.display, native, NULL, True, attribs); - if (!_sapp.glx.ctx) { - _SAPP_PANIC(LINUX_GLX_CREATE_CONTEXT_FAILED); - } - _sapp_x11_release_error_handler(); - _sapp.glx.window = _sapp.glx.CreateWindow(_sapp.x11.display, native, _sapp.x11.window, NULL); - if (!_sapp.glx.window) { - _SAPP_PANIC(LINUX_GLX_CREATE_WINDOW_FAILED); - } - _sapp_glx_make_current(); -} - -_SOKOL_PRIVATE void _sapp_glx_destroy_context(void) { - if (_sapp.glx.window) { - _sapp.glx.DestroyWindow(_sapp.x11.display, _sapp.glx.window); - _sapp.glx.window = 0; - } - if (_sapp.glx.ctx) { - _sapp.glx.DestroyContext(_sapp.x11.display, _sapp.glx.ctx); - _sapp.glx.ctx = 0; - } -} - -_SOKOL_PRIVATE void _sapp_glx_swap_buffers(void) { - _sapp.glx.SwapBuffers(_sapp.x11.display, _sapp.glx.window); -} - -_SOKOL_PRIVATE void _sapp_glx_swapinterval(int interval) { - if (_sapp.glx.EXT_swap_control) { - _sapp.glx.SwapIntervalEXT(_sapp.x11.display, _sapp.glx.window, interval); - } - else if (_sapp.glx.MESA_swap_control) { - _sapp.glx.SwapIntervalMESA(interval); - } -} - -#endif /* _SAPP_GLX */ - -_SOKOL_PRIVATE void _sapp_x11_send_event(Atom type, int a, int b, int c, int d, int e) { - XEvent event; - _sapp_clear(&event, sizeof(event)); - - event.type = ClientMessage; - event.xclient.window = _sapp.x11.window; - event.xclient.format = 32; - event.xclient.message_type = type; - event.xclient.data.l[0] = a; - event.xclient.data.l[1] = b; - event.xclient.data.l[2] = c; - event.xclient.data.l[3] = d; - event.xclient.data.l[4] = e; - - XSendEvent(_sapp.x11.display, _sapp.x11.root, - False, - SubstructureNotifyMask | SubstructureRedirectMask, - &event); -} - -_SOKOL_PRIVATE void _sapp_x11_query_window_size(void) { - XWindowAttributes attribs; - XGetWindowAttributes(_sapp.x11.display, _sapp.x11.window, &attribs); - _sapp.window_width = attribs.width; - _sapp.window_height = attribs.height; - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; -} - -_SOKOL_PRIVATE void _sapp_x11_set_fullscreen(bool enable) { - /* NOTE: this function must be called after XMapWindow (which happens in _sapp_x11_show_window()) */ - if (_sapp.x11.NET_WM_STATE && _sapp.x11.NET_WM_STATE_FULLSCREEN) { - if (enable) { - const int _NET_WM_STATE_ADD = 1; - _sapp_x11_send_event(_sapp.x11.NET_WM_STATE, - _NET_WM_STATE_ADD, - _sapp.x11.NET_WM_STATE_FULLSCREEN, - 0, 1, 0); - } - else { - const int _NET_WM_STATE_REMOVE = 0; - _sapp_x11_send_event(_sapp.x11.NET_WM_STATE, - _NET_WM_STATE_REMOVE, - _sapp.x11.NET_WM_STATE_FULLSCREEN, - 0, 1, 0); - } - } - XFlush(_sapp.x11.display); -} - -_SOKOL_PRIVATE void _sapp_x11_create_hidden_cursor(void) { - SOKOL_ASSERT(0 == _sapp.x11.hidden_cursor); - const int w = 16; - const int h = 16; - XcursorImage* img = XcursorImageCreate(w, h); - SOKOL_ASSERT(img && (img->width == 16) && (img->height == 16) && img->pixels); - img->xhot = 0; - img->yhot = 0; - const size_t num_bytes = (size_t)(w * h) * sizeof(XcursorPixel); - _sapp_clear(img->pixels, num_bytes); - _sapp.x11.hidden_cursor = XcursorImageLoadCursor(_sapp.x11.display, img); - XcursorImageDestroy(img); -} - - _SOKOL_PRIVATE void _sapp_x11_create_standard_cursor(sapp_mouse_cursor cursor, const char* name, const char* theme, int size, uint32_t fallback_native) { - SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM)); - SOKOL_ASSERT(_sapp.x11.display); - if (theme) { - XcursorImage* img = XcursorLibraryLoadImage(name, theme, size); - if (img) { - _sapp.x11.cursors[cursor] = XcursorImageLoadCursor(_sapp.x11.display, img); - XcursorImageDestroy(img); - } - } - if (0 == _sapp.x11.cursors[cursor]) { - _sapp.x11.cursors[cursor] = XCreateFontCursor(_sapp.x11.display, fallback_native); - } -} - -_SOKOL_PRIVATE void _sapp_x11_create_cursors(void) { - SOKOL_ASSERT(_sapp.x11.display); - const char* cursor_theme = XcursorGetTheme(_sapp.x11.display); - const int size = XcursorGetDefaultSize(_sapp.x11.display); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_ARROW, "default", cursor_theme, size, XC_left_ptr); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_IBEAM, "text", cursor_theme, size, XC_xterm); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_CROSSHAIR, "crosshair", cursor_theme, size, XC_crosshair); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_POINTING_HAND, "pointer", cursor_theme, size, XC_hand2); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_EW, "ew-resize", cursor_theme, size, XC_sb_h_double_arrow); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_NS, "ns-resize", cursor_theme, size, XC_sb_v_double_arrow); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_NWSE, "nwse-resize", cursor_theme, size, 0); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_NESW, "nesw-resize", cursor_theme, size, 0); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_RESIZE_ALL, "all-scroll", cursor_theme, size, XC_fleur); - _sapp_x11_create_standard_cursor(SAPP_MOUSECURSOR_NOT_ALLOWED, "no-allowed", cursor_theme, size, 0); - _sapp_x11_create_hidden_cursor(); -} - -_SOKOL_PRIVATE void _sapp_x11_destroy_cursors(void) { - SOKOL_ASSERT(_sapp.x11.display); - if (_sapp.x11.hidden_cursor) { - XFreeCursor(_sapp.x11.display, _sapp.x11.hidden_cursor); - _sapp.x11.hidden_cursor = 0; - } - for (int i = 0; i < _SAPP_MOUSECURSOR_NUM; i++) { - if (_sapp.x11.cursors[i]) { - XFreeCursor(_sapp.x11.display, _sapp.x11.cursors[i]); - _sapp.x11.cursors[i] = 0; - } - } -} - -_SOKOL_PRIVATE void _sapp_x11_toggle_fullscreen(void) { - _sapp.fullscreen = !_sapp.fullscreen; - _sapp_x11_set_fullscreen(_sapp.fullscreen); - _sapp_x11_query_window_size(); -} - -_SOKOL_PRIVATE void _sapp_x11_update_cursor(sapp_mouse_cursor cursor, bool shown) { - SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM)); - if (shown) { - if (_sapp.x11.cursors[cursor]) { - XDefineCursor(_sapp.x11.display, _sapp.x11.window, _sapp.x11.cursors[cursor]); - } - else { - XUndefineCursor(_sapp.x11.display, _sapp.x11.window); - } - } - else { - XDefineCursor(_sapp.x11.display, _sapp.x11.window, _sapp.x11.hidden_cursor); - } - XFlush(_sapp.x11.display); -} - -_SOKOL_PRIVATE void _sapp_x11_lock_mouse(bool lock) { - if (lock == _sapp.mouse.locked) { - return; - } - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - _sapp.mouse.locked = lock; - if (_sapp.mouse.locked) { - if (_sapp.x11.xi.available) { - XIEventMask em; - unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; // XIMaskLen is a macro - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - XISetMask(mask, XI_RawMotion); - XISelectEvents(_sapp.x11.display, _sapp.x11.root, &em, 1); - } - XGrabPointer(_sapp.x11.display, // display - _sapp.x11.window, // grab_window - True, // owner_events - ButtonPressMask | ButtonReleaseMask | PointerMotionMask, // event_mask - GrabModeAsync, // pointer_mode - GrabModeAsync, // keyboard_mode - _sapp.x11.window, // confine_to - _sapp.x11.hidden_cursor, // cursor - CurrentTime); // time - } - else { - if (_sapp.x11.xi.available) { - XIEventMask em; - unsigned char mask[] = { 0 }; - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - XISelectEvents(_sapp.x11.display, _sapp.x11.root, &em, 1); - } - XWarpPointer(_sapp.x11.display, None, _sapp.x11.window, 0, 0, 0, 0, (int) _sapp.mouse.x, _sapp.mouse.y); - XUngrabPointer(_sapp.x11.display, CurrentTime); - } - XFlush(_sapp.x11.display); -} - -_SOKOL_PRIVATE void _sapp_x11_update_window_title(void) { - Xutf8SetWMProperties(_sapp.x11.display, - _sapp.x11.window, - _sapp.window_title, _sapp.window_title, - NULL, 0, NULL, NULL, NULL); - XChangeProperty(_sapp.x11.display, _sapp.x11.window, - _sapp.x11.NET_WM_NAME, _sapp.x11.UTF8_STRING, 8, - PropModeReplace, - (unsigned char*)_sapp.window_title, - strlen(_sapp.window_title)); - XChangeProperty(_sapp.x11.display, _sapp.x11.window, - _sapp.x11.NET_WM_ICON_NAME, _sapp.x11.UTF8_STRING, 8, - PropModeReplace, - (unsigned char*)_sapp.window_title, - strlen(_sapp.window_title)); - XFlush(_sapp.x11.display); -} - -_SOKOL_PRIVATE void _sapp_x11_set_icon(const sapp_icon_desc* icon_desc, int num_images) { - SOKOL_ASSERT((num_images > 0) && (num_images <= SAPP_MAX_ICONIMAGES)); - int long_count = 0; - for (int i = 0; i < num_images; i++) { - const sapp_image_desc* img_desc = &icon_desc->images[i]; - long_count += 2 + (img_desc->width * img_desc->height); - } - long* icon_data = (long*) _sapp_malloc_clear((size_t)long_count * sizeof(long)); - SOKOL_ASSERT(icon_data); - long* dst = icon_data; - for (int img_index = 0; img_index < num_images; img_index++) { - const sapp_image_desc* img_desc = &icon_desc->images[img_index]; - const uint8_t* src = (const uint8_t*) img_desc->pixels.ptr; - *dst++ = img_desc->width; - *dst++ = img_desc->height; - const int num_pixels = img_desc->width * img_desc->height; - for (int pixel_index = 0; pixel_index < num_pixels; pixel_index++) { - *dst++ = ((long)(src[pixel_index * 4 + 0]) << 16) | - ((long)(src[pixel_index * 4 + 1]) << 8) | - ((long)(src[pixel_index * 4 + 2]) << 0) | - ((long)(src[pixel_index * 4 + 3]) << 24); - } - } - XChangeProperty(_sapp.x11.display, _sapp.x11.window, - _sapp.x11.NET_WM_ICON, - XA_CARDINAL, 32, - PropModeReplace, - (unsigned char*)icon_data, - long_count); - _sapp_free(icon_data); - XFlush(_sapp.x11.display); -} - -_SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) { - _sapp.x11.colormap = XCreateColormap(_sapp.x11.display, _sapp.x11.root, visual, AllocNone); - XSetWindowAttributes wa; - _sapp_clear(&wa, sizeof(wa)); - const uint32_t wamask = CWBorderPixel | CWColormap | CWEventMask; - wa.colormap = _sapp.x11.colormap; - wa.border_pixel = 0; - wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | - PointerMotionMask | ButtonPressMask | ButtonReleaseMask | - ExposureMask | FocusChangeMask | VisibilityChangeMask | - EnterWindowMask | LeaveWindowMask | PropertyChangeMask; - - int display_width = DisplayWidth(_sapp.x11.display, _sapp.x11.screen); - int display_height = DisplayHeight(_sapp.x11.display, _sapp.x11.screen); - int window_width = _sapp.window_width; - int window_height = _sapp.window_height; - if (0 == window_width) { - window_width = (display_width * 4) / 5; - } - if (0 == window_height) { - window_height = (display_height * 4) / 5; - } - int window_xpos = (display_width - window_width) / 2; - int window_ypos = (display_height - window_height) / 2; - if (window_xpos < 0) { - window_xpos = 0; - } - if (window_ypos < 0) { - window_ypos = 0; - } - _sapp_x11_grab_error_handler(); - _sapp.x11.window = XCreateWindow(_sapp.x11.display, - _sapp.x11.root, - window_xpos, - window_ypos, - (uint32_t)window_width, - (uint32_t)window_height, - 0, /* border width */ - depth, /* color depth */ - InputOutput, - visual, - wamask, - &wa); - _sapp_x11_release_error_handler(); - if (!_sapp.x11.window) { - _SAPP_PANIC(LINUX_X11_CREATE_WINDOW_FAILED); - } - Atom protocols[] = { - _sapp.x11.WM_DELETE_WINDOW - }; - XSetWMProtocols(_sapp.x11.display, _sapp.x11.window, protocols, 1); - - XSizeHints* hints = XAllocSizeHints(); - hints->flags = (PWinGravity | PPosition | PSize); - hints->win_gravity = StaticGravity; - hints->x = window_xpos; - hints->y = window_ypos; - hints->width = window_width; - hints->height = window_height; - XSetWMNormalHints(_sapp.x11.display, _sapp.x11.window, hints); - XFree(hints); - - /* announce support for drag'n'drop */ - if (_sapp.drop.enabled) { - const Atom version = _SAPP_X11_XDND_VERSION; - XChangeProperty(_sapp.x11.display, _sapp.x11.window, _sapp.x11.xdnd.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*) &version, 1); - } - _sapp_x11_update_window_title(); - _sapp_x11_query_window_size(); -} - -_SOKOL_PRIVATE void _sapp_x11_destroy_window(void) { - if (_sapp.x11.window) { - XUnmapWindow(_sapp.x11.display, _sapp.x11.window); - XDestroyWindow(_sapp.x11.display, _sapp.x11.window); - _sapp.x11.window = 0; - } - if (_sapp.x11.colormap) { - XFreeColormap(_sapp.x11.display, _sapp.x11.colormap); - _sapp.x11.colormap = 0; - } - XFlush(_sapp.x11.display); -} - -_SOKOL_PRIVATE bool _sapp_x11_window_visible(void) { - XWindowAttributes wa; - XGetWindowAttributes(_sapp.x11.display, _sapp.x11.window, &wa); - return wa.map_state == IsViewable; -} - -_SOKOL_PRIVATE void _sapp_x11_show_window(void) { - if (!_sapp_x11_window_visible()) { - XMapWindow(_sapp.x11.display, _sapp.x11.window); - XRaiseWindow(_sapp.x11.display, _sapp.x11.window); - XFlush(_sapp.x11.display); - } -} - -_SOKOL_PRIVATE void _sapp_x11_hide_window(void) { - XUnmapWindow(_sapp.x11.display, _sapp.x11.window); - XFlush(_sapp.x11.display); -} - -_SOKOL_PRIVATE unsigned long _sapp_x11_get_window_property(Window window, Atom property, Atom type, unsigned char** value) { - Atom actualType; - int actualFormat; - unsigned long itemCount, bytesAfter; - XGetWindowProperty(_sapp.x11.display, - window, - property, - 0, - LONG_MAX, - False, - type, - &actualType, - &actualFormat, - &itemCount, - &bytesAfter, - value); - return itemCount; -} - -_SOKOL_PRIVATE int _sapp_x11_get_window_state(void) { - int result = WithdrawnState; - struct { - CARD32 state; - Window icon; - } *state = NULL; - - if (_sapp_x11_get_window_property(_sapp.x11.window, _sapp.x11.WM_STATE, _sapp.x11.WM_STATE, (unsigned char**)&state) >= 2) { - result = (int)state->state; - } - if (state) { - XFree(state); - } - return result; -} - -_SOKOL_PRIVATE uint32_t _sapp_x11_key_modifier_bit(sapp_keycode key) { - switch (key) { - case SAPP_KEYCODE_LEFT_SHIFT: - case SAPP_KEYCODE_RIGHT_SHIFT: - return SAPP_MODIFIER_SHIFT; - case SAPP_KEYCODE_LEFT_CONTROL: - case SAPP_KEYCODE_RIGHT_CONTROL: - return SAPP_MODIFIER_CTRL; - case SAPP_KEYCODE_LEFT_ALT: - case SAPP_KEYCODE_RIGHT_ALT: - return SAPP_MODIFIER_ALT; - case SAPP_KEYCODE_LEFT_SUPER: - case SAPP_KEYCODE_RIGHT_SUPER: - return SAPP_MODIFIER_SUPER; - default: - return 0; - } -} - -_SOKOL_PRIVATE uint32_t _sapp_x11_button_modifier_bit(sapp_mousebutton btn) { - switch (btn) { - case SAPP_MOUSEBUTTON_LEFT: return SAPP_MODIFIER_LMB; - case SAPP_MOUSEBUTTON_RIGHT: return SAPP_MODIFIER_RMB; - case SAPP_MOUSEBUTTON_MIDDLE: return SAPP_MODIFIER_MMB; - default: return 0; - } -} - -_SOKOL_PRIVATE uint32_t _sapp_x11_mods(uint32_t x11_mods) { - uint32_t mods = 0; - if (x11_mods & ShiftMask) { - mods |= SAPP_MODIFIER_SHIFT; - } - if (x11_mods & ControlMask) { - mods |= SAPP_MODIFIER_CTRL; - } - if (x11_mods & Mod1Mask) { - mods |= SAPP_MODIFIER_ALT; - } - if (x11_mods & Mod4Mask) { - mods |= SAPP_MODIFIER_SUPER; - } - if (x11_mods & Button1Mask) { - mods |= SAPP_MODIFIER_LMB; - } - if (x11_mods & Button2Mask) { - mods |= SAPP_MODIFIER_MMB; - } - if (x11_mods & Button3Mask) { - mods |= SAPP_MODIFIER_RMB; - } - return mods; -} - -_SOKOL_PRIVATE void _sapp_x11_app_event(sapp_event_type type) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE sapp_mousebutton _sapp_x11_translate_button(const XEvent* event) { - switch (event->xbutton.button) { - case Button1: return SAPP_MOUSEBUTTON_LEFT; - case Button2: return SAPP_MOUSEBUTTON_MIDDLE; - case Button3: return SAPP_MOUSEBUTTON_RIGHT; - default: return SAPP_MOUSEBUTTON_INVALID; - } -} - -_SOKOL_PRIVATE void _sapp_x11_mouse_update(int x, int y, bool clear_dxdy) { - if (!_sapp.mouse.locked) { - const float new_x = (float) x; - const float new_y = (float) y; - if (clear_dxdy) { - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - } else if (_sapp.mouse.pos_valid) { - _sapp.mouse.dx = new_x - _sapp.mouse.x; - _sapp.mouse.dy = new_y - _sapp.mouse.y; - } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; - } -} - -_SOKOL_PRIVATE void _sapp_x11_mouse_event(sapp_event_type type, sapp_mousebutton btn, uint32_t mods) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp.event.mouse_button = btn; - _sapp.event.modifiers = mods; - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_x11_scroll_event(float x, float y, uint32_t mods) { - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); - _sapp.event.modifiers = mods; - _sapp.event.scroll_x = x; - _sapp.event.scroll_y = y; - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE void _sapp_x11_key_event(sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mods) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp.event.key_code = key; - _sapp.event.key_repeat = repeat; - _sapp.event.modifiers = mods; - _sapp_call_event(&_sapp.event); - /* check if a CLIPBOARD_PASTED event must be sent too */ - if (_sapp.clipboard.enabled && - (type == SAPP_EVENTTYPE_KEY_DOWN) && - (_sapp.event.modifiers == SAPP_MODIFIER_CTRL) && - (_sapp.event.key_code == SAPP_KEYCODE_V)) - { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); - _sapp_call_event(&_sapp.event); - } - } -} - -_SOKOL_PRIVATE void _sapp_x11_char_event(uint32_t chr, bool repeat, uint32_t mods) { - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_CHAR); - _sapp.event.char_code = chr; - _sapp.event.key_repeat = repeat; - _sapp.event.modifiers = mods; - _sapp_call_event(&_sapp.event); - } -} - -_SOKOL_PRIVATE sapp_keycode _sapp_x11_translate_key(int scancode) { - if ((scancode >= 0) && (scancode < _SAPP_X11_MAX_X11_KEYCODES)) { - return _sapp.keycodes[scancode]; - } else { - return SAPP_KEYCODE_INVALID; - } -} - -_SOKOL_PRIVATE int32_t _sapp_x11_keysym_to_unicode(KeySym keysym) { - int min = 0; - int max = sizeof(_sapp_x11_keysymtab) / sizeof(struct _sapp_x11_codepair) - 1; - int mid; - - /* First check for Latin-1 characters (1:1 mapping) */ - if ((keysym >= 0x0020 && keysym <= 0x007e) || - (keysym >= 0x00a0 && keysym <= 0x00ff)) - { - return keysym; - } - - /* Also check for directly encoded 24-bit UCS characters */ - if ((keysym & 0xff000000) == 0x01000000) { - return keysym & 0x00ffffff; - } - - /* Binary search in table */ - while (max >= min) { - mid = (min + max) / 2; - if (_sapp_x11_keysymtab[mid].keysym < keysym) { - min = mid + 1; - } - else if (_sapp_x11_keysymtab[mid].keysym > keysym) { - max = mid - 1; - } - else { - return _sapp_x11_keysymtab[mid].ucs; - } - } - - /* No matching Unicode value found */ - return -1; -} - -_SOKOL_PRIVATE bool _sapp_x11_keypress_repeat(int keycode) { - bool repeat = false; - if ((keycode >= 0) && (keycode < _SAPP_X11_MAX_X11_KEYCODES)) { - repeat = _sapp.x11.key_repeat[keycode]; - _sapp.x11.key_repeat[keycode] = true; - } - return repeat; -} - -_SOKOL_PRIVATE void _sapp_x11_keyrelease_repeat(int keycode) { - if ((keycode >= 0) && (keycode < _SAPP_X11_MAX_X11_KEYCODES)) { - _sapp.x11.key_repeat[keycode] = false; - } -} - -_SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { - SOKOL_ASSERT(src); - SOKOL_ASSERT(_sapp.drop.buffer); - - _sapp_clear_drop_buffer(); - _sapp.drop.num_files = 0; - - /* - src is (potentially percent-encoded) string made of one or multiple paths - separated by \r\n, each path starting with 'file://' - */ - bool err = false; - int src_count = 0; - char src_chr = 0; - char* dst_ptr = _sapp.drop.buffer; - const char* dst_end_ptr = dst_ptr + (_sapp.drop.max_path_length - 1); // room for terminating 0 - while (0 != (src_chr = *src++)) { - src_count++; - char dst_chr = 0; - /* check leading 'file://' */ - if (src_count <= 7) { - if (((src_count == 1) && (src_chr != 'f')) || - ((src_count == 2) && (src_chr != 'i')) || - ((src_count == 3) && (src_chr != 'l')) || - ((src_count == 4) && (src_chr != 'e')) || - ((src_count == 5) && (src_chr != ':')) || - ((src_count == 6) && (src_chr != '/')) || - ((src_count == 7) && (src_chr != '/'))) - { - _SAPP_ERROR(LINUX_X11_DROPPED_FILE_URI_WRONG_SCHEME); - err = true; - break; - } - } - else if (src_chr == '\r') { - // skip - } - else if (src_chr == '\n') { - src_count = 0; - _sapp.drop.num_files++; - // too many files is not an error - if (_sapp.drop.num_files >= _sapp.drop.max_files) { - break; - } - dst_ptr = _sapp.drop.buffer + _sapp.drop.num_files * _sapp.drop.max_path_length; - dst_end_ptr = dst_ptr + (_sapp.drop.max_path_length - 1); - } - else if ((src_chr == '%') && src[0] && src[1]) { - // a percent-encoded byte (most likely UTF-8 multibyte sequence) - const char digits[3] = { src[0], src[1], 0 }; - src += 2; - dst_chr = (char) strtol(digits, 0, 16); - } - else { - dst_chr = src_chr; - } - if (dst_chr) { - // dst_end_ptr already has adjustment for terminating zero - if (dst_ptr < dst_end_ptr) { - *dst_ptr++ = dst_chr; - } - else { - _SAPP_ERROR(DROPPED_FILE_PATH_TOO_LONG); - err = true; - break; - } - } - } - if (err) { - _sapp_clear_drop_buffer(); - _sapp.drop.num_files = 0; - return false; - } - else { - return true; - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_genericevent(XEvent* event) { - if (_sapp.mouse.locked && _sapp.x11.xi.available) { - if (event->xcookie.extension == _sapp.x11.xi.major_opcode) { - if (XGetEventData(_sapp.x11.display, &event->xcookie)) { - if (event->xcookie.evtype == XI_RawMotion) { - XIRawEvent* re = (XIRawEvent*) event->xcookie.data; - if (re->valuators.mask_len) { - const double* values = re->raw_values; - if (XIMaskIsSet(re->valuators.mask, 0)) { - _sapp.mouse.dx = (float) *values; - values++; - } - if (XIMaskIsSet(re->valuators.mask, 1)) { - _sapp.mouse.dy = (float) *values; - } - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xmotion.state)); - } - } - XFreeEventData(_sapp.x11.display, &event->xcookie); - } - } - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_focusin(XEvent* event) { - // NOTE: ignoring NotifyGrab and NotifyUngrab is same behaviour as GLFW - if ((event->xfocus.mode != NotifyGrab) && (event->xfocus.mode != NotifyUngrab)) { - _sapp_x11_app_event(SAPP_EVENTTYPE_FOCUSED); - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_focusout(XEvent* event) { - // if focus is lost for any reason, and we're in mouse locked mode, disable mouse lock - if (_sapp.mouse.locked) { - _sapp_x11_lock_mouse(false); - } - // NOTE: ignoring NotifyGrab and NotifyUngrab is same behaviour as GLFW - if ((event->xfocus.mode != NotifyGrab) && (event->xfocus.mode != NotifyUngrab)) { - _sapp_x11_app_event(SAPP_EVENTTYPE_UNFOCUSED); - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_keypress(XEvent* event) { - int keycode = (int)event->xkey.keycode; - - const sapp_keycode key = _sapp_x11_translate_key(keycode); - const bool repeat = _sapp_x11_keypress_repeat(keycode); - uint32_t mods = _sapp_x11_mods(event->xkey.state); - // X11 doesn't set modifier bit on key down, so emulate that - mods |= _sapp_x11_key_modifier_bit(key); - if (key != SAPP_KEYCODE_INVALID) { - _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_DOWN, key, repeat, mods); - } - KeySym keysym; - XLookupString(&event->xkey, NULL, 0, &keysym, NULL); - int32_t chr = _sapp_x11_keysym_to_unicode(keysym); - if (chr > 0) { - _sapp_x11_char_event((uint32_t)chr, repeat, mods); - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_keyrelease(XEvent* event) { - int keycode = (int)event->xkey.keycode; - const sapp_keycode key = _sapp_x11_translate_key(keycode); - _sapp_x11_keyrelease_repeat(keycode); - if (key != SAPP_KEYCODE_INVALID) { - uint32_t mods = _sapp_x11_mods(event->xkey.state); - // X11 doesn't clear modifier bit on key up, so emulate that - mods &= ~_sapp_x11_key_modifier_bit(key); - _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_UP, key, false, mods); - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_buttonpress(XEvent* event) { - _sapp_x11_mouse_update(event->xbutton.x, event->xbutton.y, false); - const sapp_mousebutton btn = _sapp_x11_translate_button(event); - uint32_t mods = _sapp_x11_mods(event->xbutton.state); - // X11 doesn't set modifier bit on button down, so emulate that - mods |= _sapp_x11_button_modifier_bit(btn); - if (btn != SAPP_MOUSEBUTTON_INVALID) { - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, btn, mods); - _sapp.x11.mouse_buttons |= (1 << btn); - } - else { - // might be a scroll event - switch (event->xbutton.button) { - case 4: _sapp_x11_scroll_event(0.0f, 1.0f, mods); break; - case 5: _sapp_x11_scroll_event(0.0f, -1.0f, mods); break; - case 6: _sapp_x11_scroll_event(1.0f, 0.0f, mods); break; - case 7: _sapp_x11_scroll_event(-1.0f, 0.0f, mods); break; - } - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_buttonrelease(XEvent* event) { - _sapp_x11_mouse_update(event->xbutton.x, event->xbutton.y, false); - const sapp_mousebutton btn = _sapp_x11_translate_button(event); - if (btn != SAPP_MOUSEBUTTON_INVALID) { - uint32_t mods = _sapp_x11_mods(event->xbutton.state); - // X11 doesn't clear modifier bit on button up, so emulate that - mods &= ~_sapp_x11_button_modifier_bit(btn); - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, btn, mods); - _sapp.x11.mouse_buttons &= ~(1 << btn); - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_enternotify(XEvent* event) { - // don't send enter/leave events while mouse button held down - if (0 == _sapp.x11.mouse_buttons) { - _sapp_x11_mouse_update(event->xcrossing.x, event->xcrossing.y, true); - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xcrossing.state)); - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_leavenotify(XEvent* event) { - if (0 == _sapp.x11.mouse_buttons) { - _sapp_x11_mouse_update(event->xcrossing.x, event->xcrossing.y, true); - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xcrossing.state)); - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_motionnotify(XEvent* event) { - if (!_sapp.mouse.locked) { - _sapp_x11_mouse_update(event->xmotion.x, event->xmotion.y, false); - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xmotion.state)); - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_configurenotify(XEvent* event) { - if ((event->xconfigure.width != _sapp.window_width) || (event->xconfigure.height != _sapp.window_height)) { - _sapp.window_width = event->xconfigure.width; - _sapp.window_height = event->xconfigure.height; - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; - _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED); - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_propertynotify(XEvent* event) { - if (event->xproperty.state == PropertyNewValue) { - if (event->xproperty.atom == _sapp.x11.WM_STATE) { - const int state = _sapp_x11_get_window_state(); - if (state != _sapp.x11.window_state) { - _sapp.x11.window_state = state; - if (state == IconicState) { - _sapp_x11_app_event(SAPP_EVENTTYPE_ICONIFIED); - } - else if (state == NormalState) { - _sapp_x11_app_event(SAPP_EVENTTYPE_RESTORED); - } - } - } - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_selectionnotify(XEvent* event) { - if (event->xselection.property == _sapp.x11.xdnd.XdndSelection) { - char* data = 0; - uint32_t result = _sapp_x11_get_window_property(event->xselection.requestor, - event->xselection.property, - event->xselection.target, - (unsigned char**) &data); - if (_sapp.drop.enabled && result) { - if (_sapp_x11_parse_dropped_files_list(data)) { - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - if (_sapp_events_enabled()) { - // FIXME: Figure out how to get modifier key state here. - // The XSelection event has no 'state' item, and - // XQueryKeymap() always returns a zeroed array. - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); - _sapp_call_event(&_sapp.event); - } - } - } - if (_sapp.x11.xdnd.version >= 2) { - XEvent reply; - _sapp_clear(&reply, sizeof(reply)); - reply.type = ClientMessage; - reply.xclient.window = _sapp.x11.xdnd.source; - reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long)_sapp.x11.window; - reply.xclient.data.l[1] = result; - reply.xclient.data.l[2] = (long)_sapp.x11.xdnd.XdndActionCopy; - XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); - XFlush(_sapp.x11.display); - } - } -} - -_SOKOL_PRIVATE void _sapp_x11_on_clientmessage(XEvent* event) { - if (XFilterEvent(event, None)) { - return; - } - if (event->xclient.message_type == _sapp.x11.WM_PROTOCOLS) { - const Atom protocol = (Atom)event->xclient.data.l[0]; - if (protocol == _sapp.x11.WM_DELETE_WINDOW) { - _sapp.quit_requested = true; - } - } else if (event->xclient.message_type == _sapp.x11.xdnd.XdndEnter) { - const bool is_list = 0 != (event->xclient.data.l[1] & 1); - _sapp.x11.xdnd.source = (Window)event->xclient.data.l[0]; - _sapp.x11.xdnd.version = event->xclient.data.l[1] >> 24; - _sapp.x11.xdnd.format = None; - if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { - return; - } - uint32_t count = 0; - Atom* formats = 0; - if (is_list) { - count = _sapp_x11_get_window_property(_sapp.x11.xdnd.source, _sapp.x11.xdnd.XdndTypeList, XA_ATOM, (unsigned char**)&formats); - } else { - count = 3; - formats = (Atom*) event->xclient.data.l + 2; - } - for (uint32_t i = 0; i < count; i++) { - if (formats[i] == _sapp.x11.xdnd.text_uri_list) { - _sapp.x11.xdnd.format = _sapp.x11.xdnd.text_uri_list; - break; - } - } - if (is_list && formats) { - XFree(formats); - } - } else if (event->xclient.message_type == _sapp.x11.xdnd.XdndDrop) { - if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { - return; - } - Time time = CurrentTime; - if (_sapp.x11.xdnd.format) { - if (_sapp.x11.xdnd.version >= 1) { - time = (Time)event->xclient.data.l[2]; - } - XConvertSelection(_sapp.x11.display, - _sapp.x11.xdnd.XdndSelection, - _sapp.x11.xdnd.format, - _sapp.x11.xdnd.XdndSelection, - _sapp.x11.window, - time); - } else if (_sapp.x11.xdnd.version >= 2) { - XEvent reply; - _sapp_clear(&reply, sizeof(reply)); - reply.type = ClientMessage; - reply.xclient.window = _sapp.x11.xdnd.source; - reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long)_sapp.x11.window; - reply.xclient.data.l[1] = 0; // drag was rejected - reply.xclient.data.l[2] = None; - XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); - XFlush(_sapp.x11.display); - } - } else if (event->xclient.message_type == _sapp.x11.xdnd.XdndPosition) { - // drag operation has moved over the window - // FIXME: we could track the mouse position here, but - // this isn't implemented on other platforms either so far - if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { - return; - } - XEvent reply; - _sapp_clear(&reply, sizeof(reply)); - reply.type = ClientMessage; - reply.xclient.window = _sapp.x11.xdnd.source; - reply.xclient.message_type = _sapp.x11.xdnd.XdndStatus; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long)_sapp.x11.window; - if (_sapp.x11.xdnd.format) { - /* reply that we are ready to copy the dragged data */ - reply.xclient.data.l[1] = 1; // accept with no rectangle - if (_sapp.x11.xdnd.version >= 2) { - reply.xclient.data.l[4] = (long)_sapp.x11.xdnd.XdndActionCopy; - } - } - XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); - XFlush(_sapp.x11.display); - } -} - -_SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { - switch (event->type) { - case GenericEvent: - _sapp_x11_on_genericevent(event); - break; - case FocusIn: - _sapp_x11_on_focusin(event); - break; - case FocusOut: - _sapp_x11_on_focusout(event); - break; - case KeyPress: - _sapp_x11_on_keypress(event); - break; - case KeyRelease: - _sapp_x11_on_keyrelease(event); - break; - case ButtonPress: - _sapp_x11_on_buttonpress(event); - break; - case ButtonRelease: - _sapp_x11_on_buttonrelease(event); - break; - case EnterNotify: - _sapp_x11_on_enternotify(event); - break; - case LeaveNotify: - _sapp_x11_on_leavenotify(event); - break; - case MotionNotify: - _sapp_x11_on_motionnotify(event); - break; - case ConfigureNotify: - _sapp_x11_on_configurenotify(event); - break; - case PropertyNotify: - _sapp_x11_on_propertynotify(event); - break; - case SelectionNotify: - _sapp_x11_on_selectionnotify(event); - break; - case DestroyNotify: - // not a bug - break; - case ClientMessage: - _sapp_x11_on_clientmessage(event); - break; - } -} - -#if !defined(_SAPP_GLX) - -_SOKOL_PRIVATE void _sapp_egl_init(void) { -#if defined(SOKOL_GLCORE) - if (!eglBindAPI(EGL_OPENGL_API)) { - _SAPP_PANIC(LINUX_EGL_BIND_OPENGL_API_FAILED); - } -#else - if (!eglBindAPI(EGL_OPENGL_ES_API)) { - _SAPP_PANIC(LINUX_EGL_BIND_OPENGL_ES_API_FAILED); - } -#endif - - _sapp.egl.display = eglGetDisplay((EGLNativeDisplayType)_sapp.x11.display); - if (EGL_NO_DISPLAY == _sapp.egl.display) { - _SAPP_PANIC(LINUX_EGL_GET_DISPLAY_FAILED); - } - - EGLint major, minor; - if (!eglInitialize(_sapp.egl.display, &major, &minor)) { - _SAPP_PANIC(LINUX_EGL_INITIALIZE_FAILED); - } - - EGLint sample_count = _sapp.desc.sample_count > 1 ? _sapp.desc.sample_count : 0; - EGLint alpha_size = _sapp.desc.alpha ? 8 : 0; - const EGLint config_attrs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - #if defined(SOKOL_GLCORE) - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - #elif defined(SOKOL_GLES3) - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, - #endif - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, alpha_size, - EGL_DEPTH_SIZE, 24, - EGL_STENCIL_SIZE, 8, - EGL_SAMPLE_BUFFERS, _sapp.desc.sample_count > 1 ? 1 : 0, - EGL_SAMPLES, sample_count, - EGL_NONE, - }; - - EGLConfig egl_configs[32]; - EGLint config_count; - if (!eglChooseConfig(_sapp.egl.display, config_attrs, egl_configs, 32, &config_count) || config_count == 0) { - _SAPP_PANIC(LINUX_EGL_NO_CONFIGS); - } - - EGLConfig config = egl_configs[0]; - for (int i = 0; i < config_count; ++i) { - EGLConfig c = egl_configs[i]; - EGLint r, g, b, a, d, s, n; - if (eglGetConfigAttrib(_sapp.egl.display, c, EGL_RED_SIZE, &r) && - eglGetConfigAttrib(_sapp.egl.display, c, EGL_GREEN_SIZE, &g) && - eglGetConfigAttrib(_sapp.egl.display, c, EGL_BLUE_SIZE, &b) && - eglGetConfigAttrib(_sapp.egl.display, c, EGL_ALPHA_SIZE, &a) && - eglGetConfigAttrib(_sapp.egl.display, c, EGL_DEPTH_SIZE, &d) && - eglGetConfigAttrib(_sapp.egl.display, c, EGL_STENCIL_SIZE, &s) && - eglGetConfigAttrib(_sapp.egl.display, c, EGL_SAMPLES, &n) && - (r == 8) && (g == 8) && (b == 8) && (a == alpha_size) && (d == 24) && (s == 8) && (n == sample_count)) { - config = c; - break; - } - } - - EGLint visual_id; - if (!eglGetConfigAttrib(_sapp.egl.display, config, EGL_NATIVE_VISUAL_ID, &visual_id)) { - _SAPP_PANIC(LINUX_EGL_NO_NATIVE_VISUAL); - } - - XVisualInfo visual_info_template; - _sapp_clear(&visual_info_template, sizeof(visual_info_template)); - visual_info_template.visualid = (VisualID)visual_id; - - int num_visuals; - XVisualInfo* visual_info = XGetVisualInfo(_sapp.x11.display, VisualIDMask, &visual_info_template, &num_visuals); - if (!visual_info) { - _SAPP_PANIC(LINUX_EGL_GET_VISUAL_INFO_FAILED); - } - - _sapp_x11_create_window(visual_info->visual, visual_info->depth); - XFree(visual_info); - - _sapp.egl.surface = eglCreateWindowSurface(_sapp.egl.display, config, (EGLNativeWindowType)_sapp.x11.window, NULL); - if (EGL_NO_SURFACE == _sapp.egl.surface) { - _SAPP_PANIC(LINUX_EGL_CREATE_WINDOW_SURFACE_FAILED); - } - - EGLint ctx_attrs[] = { - #if defined(SOKOL_GLCORE) - EGL_CONTEXT_MAJOR_VERSION, _sapp.desc.gl_major_version, - EGL_CONTEXT_MINOR_VERSION, _sapp.desc.gl_minor_version, - EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - #elif defined(SOKOL_GLES3) - EGL_CONTEXT_CLIENT_VERSION, 3, - #endif - EGL_NONE, - }; - - _sapp.egl.context = eglCreateContext(_sapp.egl.display, config, EGL_NO_CONTEXT, ctx_attrs); - if (EGL_NO_CONTEXT == _sapp.egl.context) { - _SAPP_PANIC(LINUX_EGL_CREATE_CONTEXT_FAILED); - } - - if (!eglMakeCurrent(_sapp.egl.display, _sapp.egl.surface, _sapp.egl.surface, _sapp.egl.context)) { - _SAPP_PANIC(LINUX_EGL_MAKE_CURRENT_FAILED); - } - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); - - eglSwapInterval(_sapp.egl.display, _sapp.swap_interval); -} - -_SOKOL_PRIVATE void _sapp_egl_destroy(void) { - if (_sapp.egl.display != EGL_NO_DISPLAY) { - eglMakeCurrent(_sapp.egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - if (_sapp.egl.context != EGL_NO_CONTEXT) { - eglDestroyContext(_sapp.egl.display, _sapp.egl.context); - _sapp.egl.context = EGL_NO_CONTEXT; - } - - if (_sapp.egl.surface != EGL_NO_SURFACE) { - eglDestroySurface(_sapp.egl.display, _sapp.egl.surface); - _sapp.egl.surface = EGL_NO_SURFACE; - } - - eglTerminate(_sapp.egl.display); - _sapp.egl.display = EGL_NO_DISPLAY; - } -} - -#endif /* _SAPP_GLX */ - -_SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { - /* The following lines are here to trigger a linker error instead of an - obscure runtime error if the user has forgotten to add -pthread to - the compiler or linker options. They have no other purpose. - */ - pthread_attr_t pthread_attr; - pthread_attr_init(&pthread_attr); - pthread_attr_destroy(&pthread_attr); - - _sapp_init_state(desc); - _sapp.x11.window_state = NormalState; - - XInitThreads(); - XrmInitialize(); - _sapp.x11.display = XOpenDisplay(NULL); - if (!_sapp.x11.display) { - _SAPP_PANIC(LINUX_X11_OPEN_DISPLAY_FAILED); - } - _sapp.x11.screen = DefaultScreen(_sapp.x11.display); - _sapp.x11.root = DefaultRootWindow(_sapp.x11.display); - _sapp_x11_query_system_dpi(); - _sapp.dpi_scale = _sapp.x11.dpi / 96.0f; - _sapp_x11_init_extensions(); - _sapp_x11_create_cursors(); - XkbSetDetectableAutoRepeat(_sapp.x11.display, true, NULL); - _sapp_x11_init_keytable(); -#if defined(_SAPP_GLX) - _sapp_glx_init(); - Visual* visual = 0; - int depth = 0; - _sapp_glx_choose_visual(&visual, &depth); - _sapp_x11_create_window(visual, depth); - _sapp_glx_create_context(); - _sapp_glx_swapinterval(_sapp.swap_interval); -#else - _sapp_egl_init(); -#endif - sapp_set_icon(&desc->icon); - _sapp.valid = true; - _sapp_x11_show_window(); - if (_sapp.fullscreen) { - _sapp_x11_set_fullscreen(true); - } - - XFlush(_sapp.x11.display); - while (!_sapp.quit_ordered) { - _sapp_timing_measure(&_sapp.timing); - int count = XPending(_sapp.x11.display); - while (count--) { - XEvent event; - XNextEvent(_sapp.x11.display, &event); - _sapp_x11_process_event(&event); - } - _sapp_frame(); -#if defined(_SAPP_GLX) - _sapp_glx_swap_buffers(); -#else - eglSwapBuffers(_sapp.egl.display, _sapp.egl.surface); -#endif - XFlush(_sapp.x11.display); - /* handle quit-requested, either from window or from sapp_request_quit() */ - if (_sapp.quit_requested && !_sapp.quit_ordered) { - /* give user code a chance to intervene */ - _sapp_x11_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED); - /* if user code hasn't intervened, quit the app */ - if (_sapp.quit_requested) { - _sapp.quit_ordered = true; - } - } - } - _sapp_call_cleanup(); -#if defined(_SAPP_GLX) - _sapp_glx_destroy_context(); -#else - _sapp_egl_destroy(); -#endif - _sapp_x11_destroy_window(); - _sapp_x11_destroy_cursors(); - XCloseDisplay(_sapp.x11.display); - _sapp_discard_state(); -} - -#if !defined(SOKOL_NO_ENTRY) -int main(int argc, char* argv[]) { - sapp_desc desc = sokol_main(argc, argv); - _sapp_linux_run(&desc); - return 0; -} -#endif /* SOKOL_NO_ENTRY */ -#endif /* _SAPP_LINUX */ - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -#if defined(SOKOL_NO_ENTRY) -SOKOL_API_IMPL void sapp_run(const sapp_desc* desc) { - SOKOL_ASSERT(desc); - #if defined(_SAPP_MACOS) - _sapp_macos_run(desc); - #elif defined(_SAPP_IOS) - _sapp_ios_run(desc); - #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_run(desc); - #elif defined(_SAPP_WIN32) - _sapp_win32_run(desc); - #elif defined(_SAPP_LINUX) - _sapp_linux_run(desc); - #else - #error "sapp_run() not supported on this platform" - #endif -} - -/* this is just a stub so the linker doesn't complain */ -sapp_desc sokol_main(int argc, char* argv[]) { - _SOKOL_UNUSED(argc); - _SOKOL_UNUSED(argv); - sapp_desc desc; - _sapp_clear(&desc, sizeof(desc)); - return desc; -} -#else -/* likewise, in normal mode, sapp_run() is just an empty stub */ -SOKOL_API_IMPL void sapp_run(const sapp_desc* desc) { - _SOKOL_UNUSED(desc); -} -#endif - -SOKOL_API_IMPL bool sapp_isvalid(void) { - return _sapp.valid; -} - -SOKOL_API_IMPL void* sapp_userdata(void) { - return _sapp.desc.user_data; -} - -SOKOL_API_IMPL sapp_desc sapp_query_desc(void) { - return _sapp.desc; -} - -SOKOL_API_IMPL uint64_t sapp_frame_count(void) { - return _sapp.frame_count; -} - -SOKOL_API_IMPL double sapp_frame_duration(void) { - return _sapp_timing_get_avg(&_sapp.timing); -} - -SOKOL_API_IMPL int sapp_width(void) { - return (_sapp.framebuffer_width > 0) ? _sapp.framebuffer_width : 1; -} - -SOKOL_API_IMPL float sapp_widthf(void) { - return (float)sapp_width(); -} - -SOKOL_API_IMPL int sapp_height(void) { - return (_sapp.framebuffer_height > 0) ? _sapp.framebuffer_height : 1; -} - -SOKOL_API_IMPL float sapp_heightf(void) { - return (float)sapp_height(); -} - -SOKOL_API_IMPL int sapp_color_format(void) { - #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) - switch (_sapp.wgpu.render_format) { - case WGPUTextureFormat_RGBA8Unorm: - return _SAPP_PIXELFORMAT_RGBA8; - case WGPUTextureFormat_BGRA8Unorm: - return _SAPP_PIXELFORMAT_BGRA8; - default: - SOKOL_UNREACHABLE; - return 0; - } - #elif defined(SOKOL_METAL) || defined(SOKOL_D3D11) - return _SAPP_PIXELFORMAT_BGRA8; - #else - return _SAPP_PIXELFORMAT_RGBA8; - #endif -} - -SOKOL_API_IMPL int sapp_depth_format(void) { - return _SAPP_PIXELFORMAT_DEPTH_STENCIL; -} - -SOKOL_API_IMPL int sapp_sample_count(void) { - return _sapp.sample_count; -} - -SOKOL_API_IMPL bool sapp_high_dpi(void) { - return _sapp.desc.high_dpi && (_sapp.dpi_scale >= 1.5f); -} - -SOKOL_API_IMPL float sapp_dpi_scale(void) { - return _sapp.dpi_scale; -} - -SOKOL_API_IMPL const void* sapp_egl_get_display(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(_SAPP_ANDROID) - return _sapp.android.display; - #elif defined(_SAPP_LINUX) && !defined(_SAPP_GLX) - return _sapp.egl.display; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_egl_get_context(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(_SAPP_ANDROID) - return _sapp.android.context; - #elif defined(_SAPP_LINUX) && !defined(_SAPP_GLX) - return _sapp.egl.context; - #else - return 0; - #endif -} - -SOKOL_API_IMPL void sapp_show_keyboard(bool show) { - #if defined(_SAPP_IOS) - _sapp_ios_show_keyboard(show); - #elif defined(_SAPP_ANDROID) - _sapp_android_show_keyboard(show); - #else - _SOKOL_UNUSED(show); - #endif -} - -SOKOL_API_IMPL bool sapp_keyboard_shown(void) { - return _sapp.onscreen_keyboard_shown; -} - -SOKOL_API_IMPL bool sapp_is_fullscreen(void) { - return _sapp.fullscreen; -} - -SOKOL_API_IMPL void sapp_toggle_fullscreen(void) { - #if defined(_SAPP_MACOS) - _sapp_macos_toggle_fullscreen(); - #elif defined(_SAPP_WIN32) - _sapp_win32_toggle_fullscreen(); - #elif defined(_SAPP_LINUX) - _sapp_x11_toggle_fullscreen(); - #endif -} - -/* NOTE that sapp_show_mouse() does not "stack" like the Win32 or macOS API functions! */ -SOKOL_API_IMPL void sapp_show_mouse(bool show) { - if (_sapp.mouse.shown != show) { - #if defined(_SAPP_MACOS) - _sapp_macos_update_cursor(_sapp.mouse.current_cursor, show); - #elif defined(_SAPP_WIN32) - _sapp_win32_update_cursor(_sapp.mouse.current_cursor, show, false); - #elif defined(_SAPP_LINUX) - _sapp_x11_update_cursor(_sapp.mouse.current_cursor, show); - #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_update_cursor(_sapp.mouse.current_cursor, show); - #endif - _sapp.mouse.shown = show; - } -} - -SOKOL_API_IMPL bool sapp_mouse_shown(void) { - return _sapp.mouse.shown; -} - -SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { - #if defined(_SAPP_MACOS) - _sapp_macos_lock_mouse(lock); - #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_lock_mouse(lock); - #elif defined(_SAPP_WIN32) - _sapp_win32_lock_mouse(lock); - #elif defined(_SAPP_LINUX) - _sapp_x11_lock_mouse(lock); - #else - _sapp.mouse.locked = lock; - #endif -} - -SOKOL_API_IMPL bool sapp_mouse_locked(void) { - return _sapp.mouse.locked; -} - -SOKOL_API_IMPL void sapp_set_mouse_cursor(sapp_mouse_cursor cursor) { - SOKOL_ASSERT((cursor >= 0) && (cursor < _SAPP_MOUSECURSOR_NUM)); - if (_sapp.mouse.current_cursor != cursor) { - #if defined(_SAPP_MACOS) - _sapp_macos_update_cursor(cursor, _sapp.mouse.shown); - #elif defined(_SAPP_WIN32) - _sapp_win32_update_cursor(cursor, _sapp.mouse.shown, false); - #elif defined(_SAPP_LINUX) - _sapp_x11_update_cursor(cursor, _sapp.mouse.shown); - #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_update_cursor(cursor, _sapp.mouse.shown); - #endif - _sapp.mouse.current_cursor = cursor; - } -} - -SOKOL_API_IMPL sapp_mouse_cursor sapp_get_mouse_cursor(void) { - return _sapp.mouse.current_cursor; -} - -SOKOL_API_IMPL void sapp_request_quit(void) { - _sapp.quit_requested = true; -} - -SOKOL_API_IMPL void sapp_cancel_quit(void) { - _sapp.quit_requested = false; -} - -SOKOL_API_IMPL void sapp_quit(void) { - _sapp.quit_ordered = true; -} - -SOKOL_API_IMPL void sapp_consume_event(void) { - _sapp.event_consumed = true; -} - -/* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */ -SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { - if (!_sapp.clipboard.enabled) { - return; - } - SOKOL_ASSERT(str); - #if defined(_SAPP_MACOS) - _sapp_macos_set_clipboard_string(str); - #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_set_clipboard_string(str); - #elif defined(_SAPP_WIN32) - _sapp_win32_set_clipboard_string(str); - #else - /* not implemented */ - #endif - _sapp_strcpy(str, _sapp.clipboard.buffer, _sapp.clipboard.buf_size); -} - -SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { - if (!_sapp.clipboard.enabled) { - return ""; - } - #if defined(_SAPP_MACOS) - return _sapp_macos_get_clipboard_string(); - #elif defined(_SAPP_EMSCRIPTEN) - return _sapp.clipboard.buffer; - #elif defined(_SAPP_WIN32) - return _sapp_win32_get_clipboard_string(); - #else - /* not implemented */ - return _sapp.clipboard.buffer; - #endif -} - -SOKOL_API_IMPL void sapp_set_window_title(const char* title) { - SOKOL_ASSERT(title); - _sapp_strcpy(title, _sapp.window_title, sizeof(_sapp.window_title)); - #if defined(_SAPP_MACOS) - _sapp_macos_update_window_title(); - #elif defined(_SAPP_WIN32) - _sapp_win32_update_window_title(); - #elif defined(_SAPP_LINUX) - _sapp_x11_update_window_title(); - #endif -} - -SOKOL_API_IMPL void sapp_set_icon(const sapp_icon_desc* desc) { - SOKOL_ASSERT(desc); - if (desc->sokol_default) { - if (0 == _sapp.default_icon_pixels) { - _sapp_setup_default_icon(); - } - SOKOL_ASSERT(0 != _sapp.default_icon_pixels); - desc = &_sapp.default_icon_desc; - } - const int num_images = _sapp_icon_num_images(desc); - if (num_images == 0) { - return; - } - SOKOL_ASSERT((num_images > 0) && (num_images <= SAPP_MAX_ICONIMAGES)); - if (!_sapp_validate_icon_desc(desc, num_images)) { - return; - } - #if defined(_SAPP_MACOS) - _sapp_macos_set_icon(desc, num_images); - #elif defined(_SAPP_WIN32) - _sapp_win32_set_icon(desc, num_images); - #elif defined(_SAPP_LINUX) - _sapp_x11_set_icon(desc, num_images); - #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_set_icon(desc, num_images); - #endif -} - -SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { - SOKOL_ASSERT(_sapp.drop.enabled); - return _sapp.drop.num_files; -} - -SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { - SOKOL_ASSERT(_sapp.drop.enabled); - SOKOL_ASSERT((index >= 0) && (index < _sapp.drop.num_files)); - SOKOL_ASSERT(_sapp.drop.buffer); - if (!_sapp.drop.enabled) { - return ""; - } - if ((index < 0) || (index >= _sapp.drop.max_files)) { - return ""; - } - return (const char*) _sapp_dropped_file_path_ptr(index); -} - -SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { - SOKOL_ASSERT(_sapp.drop.enabled); - SOKOL_ASSERT((index >= 0) && (index < _sapp.drop.num_files)); - #if defined(_SAPP_EMSCRIPTEN) - if (!_sapp.drop.enabled) { - return 0; - } - return sapp_js_dropped_file_size(index); - #else - (void)index; - return 0; - #endif -} - -SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) { - SOKOL_ASSERT(_sapp.drop.enabled); - SOKOL_ASSERT(request); - SOKOL_ASSERT(request->callback); - SOKOL_ASSERT(request->buffer.ptr); - SOKOL_ASSERT(request->buffer.size > 0); - #if defined(_SAPP_EMSCRIPTEN) - const int index = request->dropped_file_index; - sapp_html5_fetch_error error_code = SAPP_HTML5_FETCH_ERROR_NO_ERROR; - if ((index < 0) || (index >= _sapp.drop.num_files)) { - error_code = SAPP_HTML5_FETCH_ERROR_OTHER; - } - if (sapp_html5_get_dropped_file_size(index) > request->buffer.size) { - error_code = SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL; - } - if (SAPP_HTML5_FETCH_ERROR_NO_ERROR != error_code) { - _sapp_emsc_invoke_fetch_cb(index, - false, // success - (int)error_code, - request->callback, - 0, // fetched_size - (void*)request->buffer.ptr, - request->buffer.size, - request->user_data); - } - else { - sapp_js_fetch_dropped_file(index, - request->callback, - (void*)request->buffer.ptr, - request->buffer.size, - request->user_data); - } - #else - (void)request; - #endif -} - -SOKOL_API_IMPL const void* sapp_metal_get_device(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_METAL) - #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) _sapp.macos.mtl_device; - #else - const void* obj = (__bridge const void*) _sapp.ios.mtl_device; - #endif - SOKOL_ASSERT(obj); - return obj; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_metal_get_current_drawable(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_METAL) - #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view currentDrawable]; - #else - const void* obj = (__bridge const void*) [_sapp.ios.view currentDrawable]; - #endif - SOKOL_ASSERT(obj); - return obj; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_metal_get_depth_stencil_texture(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_METAL) - #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view depthStencilTexture]; - #else - const void* obj = (__bridge const void*) [_sapp.ios.view depthStencilTexture]; - #endif - return obj; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_metal_get_msaa_color_texture(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_METAL) - #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view multisampleColorTexture]; - #else - const void* obj = (__bridge const void*) [_sapp.ios.view multisampleColorTexture]; - #endif - return obj; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_macos_get_window(void) { - #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) _sapp.macos.window; - SOKOL_ASSERT(obj); - return obj; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_ios_get_window(void) { - #if defined(_SAPP_IOS) - const void* obj = (__bridge const void*) _sapp.ios.window; - SOKOL_ASSERT(obj); - return obj; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_d3d11_get_device(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - return _sapp.d3d11.device; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_d3d11_get_device_context(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - return _sapp.d3d11.device_context; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_d3d11_get_swap_chain(void) { - SOKOL_ASSERT(_sapp.valid); -#if defined(SOKOL_D3D11) - return _sapp.d3d11.swap_chain; -#else - return 0; -#endif -} - -SOKOL_API_IMPL const void* sapp_d3d11_get_render_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.d3d11.msaa_rtv); - return _sapp.d3d11.msaa_rtv; - } else { - SOKOL_ASSERT(_sapp.d3d11.rtv); - return _sapp.d3d11.rtv; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_d3d11_get_resolve_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.d3d11.rtv); - return _sapp.d3d11.rtv; - } else { - return 0; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_d3d11_get_depth_stencil_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_D3D11) - return _sapp.d3d11.dsv; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_win32_get_hwnd(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(_SAPP_WIN32) - return _sapp.win32.hwnd; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_wgpu_get_device(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) - return (const void*) _sapp.wgpu.device; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_wgpu_get_render_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.wgpu.msaa_view); - return (const void*) _sapp.wgpu.msaa_view; - } else { - SOKOL_ASSERT(_sapp.wgpu.swapchain_view); - return (const void*) _sapp.wgpu.swapchain_view; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_wgpu_get_resolve_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.wgpu.swapchain_view); - return (const void*) _sapp.wgpu.swapchain_view; - } else { - return 0; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_wgpu_get_depth_stencil_view(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) - return (const void*) _sapp.wgpu.depth_stencil_view; - #else - return 0; - #endif -} - -SOKOL_API_IMPL uint32_t sapp_gl_get_framebuffer(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(_SAPP_ANY_GL) - return _sapp.gl.framebuffer; - #else - return 0; - #endif -} - -SOKOL_API_IMPL int sapp_gl_get_major_version(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_GLCORE) - return _sapp.desc.gl_major_version; - #else - return 0; - #endif -} - -SOKOL_API_IMPL int sapp_gl_get_minor_version(void) { - SOKOL_ASSERT(_sapp.valid); - #if defined(SOKOL_GLCORE) - return _sapp.desc.gl_minor_version; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sapp_android_get_native_activity(void) { - // NOTE: _sapp.valid is not asserted here because sapp_android_get_native_activity() - // needs to be callable from within sokol_main() (see: https://github.com/floooh/sokol/issues/708) - #if defined(_SAPP_ANDROID) - return (void*)_sapp.android.activity; - #else - return 0; - #endif -} - -SOKOL_API_IMPL void sapp_html5_ask_leave_site(bool ask) { - _sapp.html5_ask_leave_site = ask; -} - -#endif /* SOKOL_APP_IMPL */ diff --git a/source/thirdparty/sokol/sokol_args.h b/source/thirdparty/sokol/sokol_args.h deleted file mode 100644 index b5b4d47c..00000000 --- a/source/thirdparty/sokol/sokol_args.h +++ /dev/null @@ -1,867 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_ARGS_IMPL) -#define SOKOL_ARGS_IMPL -#endif -#ifndef SOKOL_ARGS_INCLUDED -/* - sokol_args.h -- cross-platform key/value arg-parsing for web and native - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_ARGS_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - Optionally provide the following defines with your own implementations: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_ARGS_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_ARGS_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_args.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_ARGS_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - OVERVIEW - ======== - sokol_args.h provides a simple unified argument parsing API for WebAssembly and - native apps. - - When running as a WebAssembly app, arguments are taken from the page URL: - - https://floooh.github.io/tiny8bit/kc85.html?type=kc85_3&mod=m022&snapshot=kc85/jungle.kcc - - The same arguments provided to a command line app: - - kc85 type=kc85_3 mod=m022 snapshot=kc85/jungle.kcc - - You can also use standalone keys without value: - - https://floooh.github.io/tiny8bit/kc85.html?bla&blub - - On the command line: - - kc85 bla blub - - Such value-less keys are reported as the value being an empty string, but they - can be tested with `sapp_exists("bla")` or `sapp_boolean("blub")`. - - ARGUMENT FORMATTING - =================== - On the web platform, arguments must be formatted as a valid URL query string - with 'percent encoding' used for special characters. - - Strings are expected to be UTF-8 encoded (although sokol_args.h doesn't - contain any special UTF-8 handling). See below on how to obtain - UTF-8 encoded argc/argv values on Windows when using WinMain() as - entry point. - - On native platforms the following rules must be followed: - - Arguments have the general form - - key=value - - or - - key - - When a key has no value, the value will be assigned an empty string. - - Key/value pairs are separated by 'whitespace', valid whitespace - characters are space and tab. - - Whitespace characters in front and after the separating '=' character - are ignored: - - key = value - - ...is the same as - - key=value - - The 'key' string must be a simple string without escape sequences or whitespace. - - The 'value' string can be quoted, and quoted value strings can contain - whitespace: - - key = 'single-quoted value' - key = "double-quoted value" - - Single-quoted value strings can contain double quotes, and vice-versa: - - key = 'single-quoted value "can contain double-quotes"' - key = "double-quoted value 'can contain single-quotes'" - - Note that correct quoting can be tricky on some shells, since command - shells may remove quotes, unless they're escaped. - - Value strings can contain a small selection of escape sequences: - - \n - newline - \r - carriage return - \t - tab - \\ - escaped backslash - - (more escape codes may be added in the future). - - CODE EXAMPLE - ============ - - int main(int argc, char* argv[]) { - // initialize sokol_args with default parameters - sargs_setup(&(sargs_desc){ - .argc = argc, - .argv = argv - }); - - // check if a key exists... - if (sargs_exists("bla")) { - ... - } - - // get value string for key, if not found, return empty string "" - const char* val0 = sargs_value("bla"); - - // get value string for key, or default string if key not found - const char* val1 = sargs_value_def("bla", "default_value"); - - // check if a key matches expected value - if (sargs_equals("type", "kc85_4")) { - ... - } - - // check if a key's value is "true", "yes" or "on" or if this is a standalone key - if (sargs_boolean("joystick_enabled")) { - ... - } - - // iterate over keys and values - for (int i = 0; i < sargs_num_args(); i++) { - printf("key: %s, value: %s\n", sargs_key_at(i), sargs_value_at(i)); - } - - // lookup argument index by key string, will return -1 if key - // is not found, sargs_key_at() and sargs_value_at() will return - // an empty string for invalid indices - int index = sargs_find("bla"); - printf("key: %s, value: %s\n", sargs_key_at(index), sargs_value_at(index)); - - // shutdown sokol-args - sargs_shutdown(); - } - - WINMAIN AND ARGC / ARGV - ======================= - On Windows with WinMain() based apps, getting UTF8-encoded command line - arguments is a bit more complicated: - - First call GetCommandLineW(), this returns the entire command line - as UTF-16 string. Then call CommandLineToArgvW(), this parses the - command line string into the usual argc/argv format (but in UTF-16). - Finally convert the UTF-16 strings in argv[] into UTF-8 via - WideCharToMultiByte(). - - See the function _sapp_win32_command_line_to_utf8_argv() in sokol_app.h - for example code how to do this (if you're using sokol_app.h, it will - already convert the command line arguments to UTF-8 for you of course, - so you can plug them directly into sokol_app.h). - - API DOCUMENTATION - ================= - void sargs_setup(const sargs_desc* desc) - Initialize sokol_args, desc contains the following configuration - parameters: - int argc - the main function's argc parameter - char** argv - the main function's argv parameter - int max_args - max number of key/value pairs, default is 16 - int buf_size - size of the internal string buffer, default is 16384 - - Note that on the web, argc and argv will be ignored and the arguments - will be taken from the page URL instead. - - sargs_setup() will allocate 2 memory chunks: one for keeping track - of the key/value args of size 'max_args*8', and a string buffer - of size 'buf_size'. - - void sargs_shutdown(void) - Shutdown sokol-args and free any allocated memory. - - bool sargs_isvalid(void) - Return true between sargs_setup() and sargs_shutdown() - - bool sargs_exists(const char* key) - Test if an argument exists by its key name. - - const char* sargs_value(const char* key) - Return value associated with key. Returns an empty string ("") if the - key doesn't exist, or if the key doesn't have a value. - - const char* sargs_value_def(const char* key, const char* default) - Return value associated with key, or the provided default value if the - key doesn't exist, or this is a value-less key. - - bool sargs_equals(const char* key, const char* val); - Return true if the value associated with key matches - the 'val' argument. - - bool sargs_boolean(const char* key) - Return true if the value string of 'key' is one of 'true', 'yes', 'on', - or this is a key without value. - - int sargs_find(const char* key) - Find argument by key name and return its index, or -1 if not found. - - int sargs_num_args(void) - Return number of key/value pairs. - - const char* sargs_key_at(int index) - Return the key name of argument at index. Returns empty string if - is index is outside range. - - const char* sargs_value_at(int index) - Return the value of argument at index. Returns empty string - if the key at index has no value, or the index is out-of-range. - - - 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); - } - - ... - sargs_setup(&(sargs_desc){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ..., - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_args.h - itself though, not any allocations in OS libraries. - - TODO - ==== - - parsing 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. -*/ -#define SOKOL_ARGS_INCLUDED (1) -#include -#include -#include // size_t - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_ARGS_API_DECL) -#define SOKOL_ARGS_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_ARGS_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_ARGS_IMPL) -#define SOKOL_ARGS_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_ARGS_API_DECL __declspec(dllimport) -#else -#define SOKOL_ARGS_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - sargs_allocator - - Used in sargs_desc to provide custom memory-alloc and -free functions - to sokol_args.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct sargs_allocator { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sargs_allocator; - -typedef struct sargs_desc { - int argc; - char** argv; - int max_args; - int buf_size; - sargs_allocator allocator; -} sargs_desc; - -/* setup sokol-args */ -SOKOL_ARGS_API_DECL void sargs_setup(const sargs_desc* desc); -/* shutdown sokol-args */ -SOKOL_ARGS_API_DECL void sargs_shutdown(void); -/* true between sargs_setup() and sargs_shutdown() */ -SOKOL_ARGS_API_DECL bool sargs_isvalid(void); -/* test if an argument exists by key name */ -SOKOL_ARGS_API_DECL bool sargs_exists(const char* key); -/* get value by key name, return empty string if key doesn't exist or an existing key has no value */ -SOKOL_ARGS_API_DECL const char* sargs_value(const char* key); -/* get value by key name, return provided default if key doesn't exist or has no value */ -SOKOL_ARGS_API_DECL const char* sargs_value_def(const char* key, const char* def); -/* return true if val arg matches the value associated with key */ -SOKOL_ARGS_API_DECL bool sargs_equals(const char* key, const char* val); -/* return true if key's value is "true", "yes", "on" or an existing key has no value */ -SOKOL_ARGS_API_DECL bool sargs_boolean(const char* key); -/* get index of arg by key name, return -1 if not exists */ -SOKOL_ARGS_API_DECL int sargs_find(const char* key); -/* get number of parsed arguments */ -SOKOL_ARGS_API_DECL int sargs_num_args(void); -/* get key name of argument at index, or empty string */ -SOKOL_ARGS_API_DECL const char* sargs_key_at(int index); -/* get value string of argument at index, or empty string */ -SOKOL_ARGS_API_DECL const char* sargs_value_at(int index); - -#ifdef __cplusplus -} /* extern "C" */ - -/* reference-based equivalents for c++ */ -inline void sargs_setup(const sargs_desc& desc) { return sargs_setup(&desc); } - -#endif -#endif // SOKOL_ARGS_INCLUDED - -/*--- IMPLEMENTATION ---------------------------------------------------------*/ -#ifdef SOKOL_ARGS_IMPL -#define SOKOL_ARGS_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sargs_desc.allocator to override memory allocation functions" -#endif - -#include // memset, strcmp -#include // malloc, free - -#if defined(__EMSCRIPTEN__) -#include -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -#define _sargs_def(val, def) (((val) == 0) ? (def) : (val)) - -#define _SARGS_MAX_ARGS_DEF (16) -#define _SARGS_BUF_SIZE_DEF (16*1024) - -/* parser state */ -#define _SARGS_EXPECT_KEY (1<<0) -#define _SARGS_EXPECT_SEP (1<<1) -#define _SARGS_EXPECT_VAL (1<<2) -#define _SARGS_PARSING_KEY (1<<3) -#define _SARGS_PARSING_VAL (1<<4) -#define _SARGS_ERROR (1<<5) - -/* a key/value pair struct */ -typedef struct { - int key; /* index to start of key string in buf */ - int val; /* index to start of value string in buf */ -} _sargs_kvp_t; - -/* sokol-args state */ -typedef struct { - int max_args; /* number of key/value pairs in args array */ - int num_args; /* number of valid items in args array */ - _sargs_kvp_t* args; /* key/value pair array */ - int buf_size; /* size of buffer in bytes */ - int buf_pos; /* current buffer position */ - char* buf; /* character buffer, first char is reserved and zero for 'empty string' */ - bool valid; - uint32_t parse_state; - char quote; /* current quote char, 0 if not in a quote */ - bool in_escape; /* currently in an escape sequence */ - sargs_allocator allocator; -} _sargs_state_t; -static _sargs_state_t _sargs; - -/*== PRIVATE IMPLEMENTATION FUNCTIONS ========================================*/ -_SOKOL_PRIVATE void _sargs_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -_SOKOL_PRIVATE void* _sargs_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_sargs.allocator.alloc_fn) { - ptr = _sargs.allocator.alloc_fn(size, _sargs.allocator.user_data); - } else { - ptr = malloc(size); - } - SOKOL_ASSERT(ptr); - return ptr; -} - -_SOKOL_PRIVATE void* _sargs_malloc_clear(size_t size) { - void* ptr = _sargs_malloc(size); - _sargs_clear(ptr, size); - return ptr; -} - -_SOKOL_PRIVATE void _sargs_free(void* ptr) { - if (_sargs.allocator.free_fn) { - _sargs.allocator.free_fn(ptr, _sargs.allocator.user_data); - } else { - free(ptr); - } -} - -_SOKOL_PRIVATE void _sargs_putc(char c) { - if ((_sargs.buf_pos+2) < _sargs.buf_size) { - _sargs.buf[_sargs.buf_pos++] = c; - } -} - -_SOKOL_PRIVATE const char* _sargs_str(int index) { - SOKOL_ASSERT((index >= 0) && (index < _sargs.buf_size)); - return &_sargs.buf[index]; -} - -/*-- argument parser functions ------------------*/ -_SOKOL_PRIVATE void _sargs_expect_key(void) { - _sargs.parse_state = _SARGS_EXPECT_KEY; -} - -_SOKOL_PRIVATE bool _sargs_key_expected(void) { - return 0 != (_sargs.parse_state & _SARGS_EXPECT_KEY); -} - -_SOKOL_PRIVATE void _sargs_expect_val(void) { - _sargs.parse_state = _SARGS_EXPECT_VAL; -} - -_SOKOL_PRIVATE bool _sargs_val_expected(void) { - return 0 != (_sargs.parse_state & _SARGS_EXPECT_VAL); -} - -_SOKOL_PRIVATE void _sargs_expect_sep_or_key(void) { - _sargs.parse_state = _SARGS_EXPECT_SEP | _SARGS_EXPECT_KEY; -} - -_SOKOL_PRIVATE bool _sargs_any_expected(void) { - return 0 != (_sargs.parse_state & (_SARGS_EXPECT_KEY | _SARGS_EXPECT_VAL | _SARGS_EXPECT_SEP)); -} - -_SOKOL_PRIVATE bool _sargs_is_separator(char c) { - return c == '='; -} - -_SOKOL_PRIVATE bool _sargs_is_quote(char c) { - if (0 == _sargs.quote) { - return (c == '\'') || (c == '"'); - } - else { - return c == _sargs.quote; - } -} - -_SOKOL_PRIVATE void _sargs_begin_quote(char c) { - _sargs.quote = c; -} - -_SOKOL_PRIVATE void _sargs_end_quote(void) { - _sargs.quote = 0; -} - -_SOKOL_PRIVATE bool _sargs_in_quotes(void) { - return 0 != _sargs.quote; -} - -_SOKOL_PRIVATE bool _sargs_is_whitespace(char c) { - return !_sargs_in_quotes() && ((c == ' ') || (c == '\t')); -} - -_SOKOL_PRIVATE void _sargs_start_key(void) { - SOKOL_ASSERT((_sargs.num_args >= 0) && (_sargs.num_args < _sargs.max_args)); - _sargs.parse_state = _SARGS_PARSING_KEY; - _sargs.args[_sargs.num_args].key = _sargs.buf_pos; -} - -_SOKOL_PRIVATE void _sargs_end_key(void) { - SOKOL_ASSERT((_sargs.num_args >= 0) && (_sargs.num_args < _sargs.max_args)); - _sargs_putc(0); - // declare val as empty string in case this is a key-only arg - _sargs.args[_sargs.num_args].val = _sargs.buf_pos - 1; - _sargs.num_args++; - _sargs.parse_state = 0; -} - -_SOKOL_PRIVATE bool _sargs_parsing_key(void) { - return 0 != (_sargs.parse_state & _SARGS_PARSING_KEY); -} - -_SOKOL_PRIVATE void _sargs_start_val(void) { - SOKOL_ASSERT((_sargs.num_args > 0) && (_sargs.num_args <= _sargs.max_args)); - _sargs.parse_state = _SARGS_PARSING_VAL; - _sargs.args[_sargs.num_args - 1].val = _sargs.buf_pos; -} - -_SOKOL_PRIVATE void _sargs_end_val(void) { - _sargs_putc(0); - _sargs.parse_state = 0; -} - -_SOKOL_PRIVATE bool _sargs_is_escape(char c) { - return '\\' == c; -} - -_SOKOL_PRIVATE void _sargs_start_escape(void) { - _sargs.in_escape = true; -} - -_SOKOL_PRIVATE bool _sargs_in_escape(void) { - return _sargs.in_escape; -} - -_SOKOL_PRIVATE char _sargs_escape(char c) { - switch (c) { - case 'n': return '\n'; - case 't': return '\t'; - case 'r': return '\r'; - case '\\': return '\\'; - default: return c; - } -} - -_SOKOL_PRIVATE void _sargs_end_escape(void) { - _sargs.in_escape = false; -} - -_SOKOL_PRIVATE bool _sargs_parsing_val(void) { - return 0 != (_sargs.parse_state & _SARGS_PARSING_VAL); -} - -_SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) { - char c; - while (0 != (c = *src++)) { - if (_sargs_in_escape()) { - c = _sargs_escape(c); - _sargs_end_escape(); - } - else if (_sargs_is_escape(c)) { - _sargs_start_escape(); - continue; - } - if (_sargs_any_expected()) { - if (!_sargs_is_whitespace(c)) { - /* start of key, value or separator */ - if (_sargs_is_separator(c)) { - /* skip separator and expect value */ - _sargs_expect_val(); - continue; - } - else if (_sargs_key_expected()) { - /* start of new key */ - _sargs_start_key(); - } - else if (_sargs_val_expected()) { - /* start of value */ - if (_sargs_is_quote(c)) { - _sargs_begin_quote(c); - continue; - } - _sargs_start_val(); - } - } - else { - /* skip white space */ - continue; - } - } - else if (_sargs_parsing_key()) { - if (_sargs_is_whitespace(c) || _sargs_is_separator(c)) { - /* end of key string */ - _sargs_end_key(); - if (_sargs_is_separator(c)) { - _sargs_expect_val(); - } - else { - _sargs_expect_sep_or_key(); - } - continue; - } - } - else if (_sargs_parsing_val()) { - if (_sargs_in_quotes()) { - /* when in quotes, whitespace is a normal character - and a matching quote ends the value string - */ - if (_sargs_is_quote(c)) { - _sargs_end_quote(); - _sargs_end_val(); - _sargs_expect_key(); - continue; - } - } - else if (_sargs_is_whitespace(c)) { - /* end of value string (no quotes) */ - _sargs_end_val(); - _sargs_expect_key(); - continue; - } - } - _sargs_putc(c); - } - if (_sargs_parsing_key()) { - _sargs_end_key(); - _sargs_expect_sep_or_key(); - } - else if (_sargs_parsing_val() && !_sargs_in_quotes()) { - _sargs_end_val(); - _sargs_expect_key(); - } - return true; -} - -_SOKOL_PRIVATE bool _sargs_parse_cargs(int argc, const char** argv) { - _sargs_expect_key(); - bool retval = true; - for (int i = 1; i < argc; i++) { - retval &= _sargs_parse_carg(argv[i]); - } - _sargs.parse_state = 0; - return retval; -} - -/*-- EMSCRIPTEN IMPLEMENTATION -----------------------------------------------*/ -#if defined(__EMSCRIPTEN__) - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(EM_JS_DEPS) -EM_JS_DEPS(sokol_audio, "$withStackSave,$stringToUTF8OnStack"); -#endif - -EMSCRIPTEN_KEEPALIVE void _sargs_add_kvp(const char* key, const char* val) { - SOKOL_ASSERT(_sargs.valid && key && val); - if (_sargs.num_args >= _sargs.max_args) { - return; - } - - /* copy key string */ - char c; - _sargs.args[_sargs.num_args].key = _sargs.buf_pos; - const char* ptr = key; - while (0 != (c = *ptr++)) { - _sargs_putc(c); - } - _sargs_putc(0); - - /* copy value string */ - _sargs.args[_sargs.num_args].val = _sargs.buf_pos; - ptr = val; - while (0 != (c = *ptr++)) { - _sargs_putc(c); - } - _sargs_putc(0); - - _sargs.num_args++; -} -#ifdef __cplusplus -} /* extern "C" */ -#endif - -/* JS function to extract arguments from the page URL */ -EM_JS(void, sargs_js_parse_url, (void), { - const params = new URLSearchParams(window.location.search).entries(); - for (let p = params.next(); !p.done; p = params.next()) { - const key = p.value[0]; - const val = p.value[1]; - withStackSave(() => { - const key_cstr = stringToUTF8OnStack(key); - const val_cstr = stringToUTF8OnStack(val); - __sargs_add_kvp(key_cstr, val_cstr) - }); - } -}); - -#endif /* EMSCRIPTEN */ - -/*== PUBLIC IMPLEMENTATION FUNCTIONS =========================================*/ -SOKOL_API_IMPL void sargs_setup(const sargs_desc* desc) { - SOKOL_ASSERT(desc); - _sargs_clear(&_sargs, sizeof(_sargs)); - _sargs.max_args = _sargs_def(desc->max_args, _SARGS_MAX_ARGS_DEF); - _sargs.buf_size = _sargs_def(desc->buf_size, _SARGS_BUF_SIZE_DEF); - SOKOL_ASSERT(_sargs.buf_size > 8); - _sargs.args = (_sargs_kvp_t*) _sargs_malloc_clear((size_t)_sargs.max_args * sizeof(_sargs_kvp_t)); - _sargs.buf = (char*) _sargs_malloc_clear((size_t)_sargs.buf_size * sizeof(char)); - /* the first character in buf is reserved and always zero, this is the 'empty string' */ - _sargs.buf_pos = 1; - _sargs.allocator = desc->allocator; - _sargs.valid = true; - - /* parse argc/argv */ - _sargs_parse_cargs(desc->argc, (const char**) desc->argv); - - #if defined(__EMSCRIPTEN__) - /* on emscripten, also parse the page URL*/ - sargs_js_parse_url(); - #endif -} - -SOKOL_API_IMPL void sargs_shutdown(void) { - SOKOL_ASSERT(_sargs.valid); - if (_sargs.args) { - _sargs_free(_sargs.args); - _sargs.args = 0; - } - if (_sargs.buf) { - _sargs_free(_sargs.buf); - _sargs.buf = 0; - } - _sargs.valid = false; -} - -SOKOL_API_IMPL bool sargs_isvalid(void) { - return _sargs.valid; -} - -SOKOL_API_IMPL int sargs_find(const char* key) { - SOKOL_ASSERT(_sargs.valid && key); - for (int i = 0; i < _sargs.num_args; i++) { - if (0 == strcmp(_sargs_str(_sargs.args[i].key), key)) { - return i; - } - } - return -1; -} - -SOKOL_API_IMPL int sargs_num_args(void) { - SOKOL_ASSERT(_sargs.valid); - return _sargs.num_args; -} - -SOKOL_API_IMPL const char* sargs_key_at(int index) { - SOKOL_ASSERT(_sargs.valid); - if ((index >= 0) && (index < _sargs.num_args)) { - return _sargs_str(_sargs.args[index].key); - } - else { - /* index 0 is always the empty string */ - return _sargs_str(0); - } -} - -SOKOL_API_IMPL const char* sargs_value_at(int index) { - SOKOL_ASSERT(_sargs.valid); - if ((index >= 0) && (index < _sargs.num_args)) { - return _sargs_str(_sargs.args[index].val); - } - else { - /* index 0 is always the empty string */ - return _sargs_str(0); - } -} - -SOKOL_API_IMPL bool sargs_exists(const char* key) { - SOKOL_ASSERT(_sargs.valid && key); - return -1 != sargs_find(key); -} - -SOKOL_API_IMPL const char* sargs_value(const char* key) { - SOKOL_ASSERT(_sargs.valid && key); - return sargs_value_at(sargs_find(key)); -} - -SOKOL_API_IMPL const char* sargs_value_def(const char* key, const char* def) { - SOKOL_ASSERT(_sargs.valid && key && def); - int arg_index = sargs_find(key); - if (-1 != arg_index) { - const char* res = sargs_value_at(arg_index); - SOKOL_ASSERT(res); - if (res[0] == 0) { - return def; - } else { - return res; - } - } - else { - return def; - } -} - -SOKOL_API_IMPL bool sargs_equals(const char* key, const char* val) { - SOKOL_ASSERT(_sargs.valid && key && val); - return 0 == strcmp(sargs_value(key), val); -} - -SOKOL_API_IMPL bool sargs_boolean(const char* key) { - if (sargs_exists(key)) { - const char* val = sargs_value(key); - return (0 == strcmp("true", val)) || - (0 == strcmp("yes", val)) || - (0 == strcmp("on", val)) || - (0 == strcmp("", val)); - } else { - return false; - } -} - -#endif /* SOKOL_ARGS_IMPL */ diff --git a/source/thirdparty/sokol/sokol_audio.h b/source/thirdparty/sokol/sokol_audio.h deleted file mode 100644 index aca49422..00000000 --- a/source/thirdparty/sokol/sokol_audio.h +++ /dev/null @@ -1,2612 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_AUDIO_IMPL) -#define SOKOL_AUDIO_IMPL -#endif -#ifndef SOKOL_AUDIO_INCLUDED -/* - sokol_audio.h -- cross-platform audio-streaming API - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_AUDIO_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - Optionally provide the following defines with your own implementations: - - SOKOL_DUMMY_BACKEND - use a dummy backend - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_AUDIO_API_DECL- public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_AUDIO_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - SAUDIO_RING_MAX_SLOTS - max number of slots in the push-audio ring buffer (default 1024) - SAUDIO_OSX_USE_SYSTEM_HEADERS - define this to force inclusion of system headers on - macOS instead of using embedded CoreAudio declarations - SAUDIO_ANDROID_AAUDIO - on Android, select the AAudio backend (default) - SAUDIO_ANDROID_SLES - on Android, select the OpenSLES backend - - If sokol_audio.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_AUDIO_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - Link with the following libraries: - - - on macOS: AudioToolbox - - on iOS: AudioToolbox, AVFoundation - - on FreeBSD: asound - - on Linux: asound - - on Android: link with OpenSLES or aaudio - - on Windows with MSVC or Clang toolchain: no action needed, libs are defined in-source via pragma-comment-lib - - on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' and link with -lole32 - - FEATURE OVERVIEW - ================ - You provide a mono- or stereo-stream of 32-bit float samples, which - Sokol Audio feeds into platform-specific audio backends: - - - Windows: WASAPI - - Linux: ALSA - - FreeBSD: ALSA - - macOS: CoreAudio - - iOS: CoreAudio+AVAudioSession - - emscripten: WebAudio with ScriptProcessorNode - - Android: AAudio (default) or OpenSLES, select at build time - - Sokol Audio will not do any buffer mixing or volume control, if you have - multiple independent input streams of sample data you need to perform the - mixing yourself before forwarding the data to Sokol Audio. - - There are two mutually exclusive ways to provide the sample data: - - 1. Callback model: You provide a callback function, which will be called - when Sokol Audio needs new samples. On all platforms except emscripten, - this function is called from a separate thread. - 2. Push model: Your code pushes small blocks of sample data from your - main loop or a thread you created. The pushed data is stored in - a ring buffer where it is pulled by the backend code when - needed. - - The callback model is preferred because it is the most direct way to - feed sample data into the audio backends and also has less moving parts - (there is no ring buffer between your code and the audio backend). - - Sometimes it is not possible to generate the audio stream directly in a - callback function running in a separate thread, for such cases Sokol Audio - provides the push-model as a convenience. - - SOKOL AUDIO, SOLOUD AND MINIAUDIO - ================================= - The WASAPI, ALSA, OpenSLES and CoreAudio backend code has been taken from the - SoLoud library (with some modifications, so any bugs in there are most - likely my fault). If you need a more fully-featured audio solution, check - out SoLoud, it's excellent: - - https://github.com/jarikomppa/soloud - - Another alternative which feature-wise is somewhere inbetween SoLoud and - sokol-audio might be MiniAudio: - - https://github.com/mackron/miniaudio - - GLOSSARY - ======== - - stream buffer: - The internal audio data buffer, usually provided by the backend API. The - size of the stream buffer defines the base latency, smaller buffers have - lower latency but may cause audio glitches. Bigger buffers reduce or - eliminate glitches, but have a higher base latency. - - - stream callback: - Optional callback function which is called by Sokol Audio when it - needs new samples. On Windows, macOS/iOS and Linux, this is called in - a separate thread, on WebAudio, this is called per-frame in the - browser thread. - - - channel: - A discrete track of audio data, currently 1-channel (mono) and - 2-channel (stereo) is supported and tested. - - - sample: - The magnitude of an audio signal on one channel at a given time. In - Sokol Audio, samples are 32-bit float numbers in the range -1.0 to - +1.0. - - - frame: - The tightly packed set of samples for all channels at a given time. - For mono 1 frame is 1 sample. For stereo, 1 frame is 2 samples. - - - packet: - In Sokol Audio, a small chunk of audio data that is moved from the - main thread to the audio streaming thread in order to decouple the - rate at which the main thread provides new audio data, and the - streaming thread consuming audio data. - - WORKING WITH SOKOL AUDIO - ======================== - First call saudio_setup() with your preferred audio playback options. - In most cases you can stick with the default values, these provide - a good balance between low-latency and glitch-free playback - on all audio backends. - - You should always provide a logging callback to be aware of any - warnings and errors. The easiest way is to use sokol_log.h for this: - - #include "sokol_log.h" - // ... - saudio_setup(&(saudio_desc){ - .logger = { - .func = slog_func, - } - }); - - If you want to use the callback-model, you need to provide a stream - callback function either in saudio_desc.stream_cb or saudio_desc.stream_userdata_cb, - otherwise keep both function pointers zero-initialized. - - Use push model and default playback parameters: - - saudio_setup(&(saudio_desc){ .logger.func = slog_func }); - - Use stream callback model and default playback parameters: - - saudio_setup(&(saudio_desc){ - .stream_cb = my_stream_callback - .logger.func = slog_func, - }); - - The standard stream callback doesn't have a user data argument, if you want - that, use the alternative stream_userdata_cb and also set the user_data pointer: - - saudio_setup(&(saudio_desc){ - .stream_userdata_cb = my_stream_callback, - .user_data = &my_data - .logger.func = slog_func, - }); - - The following playback parameters can be provided through the - saudio_desc struct: - - General parameters (both for stream-callback and push-model): - - int sample_rate -- the sample rate in Hz, default: 44100 - int num_channels -- number of channels, default: 1 (mono) - int buffer_frames -- number of frames in streaming buffer, default: 2048 - - The stream callback prototype (either with or without userdata): - - void (*stream_cb)(float* buffer, int num_frames, int num_channels) - void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data) - Function pointer to the user-provide stream callback. - - Push-model parameters: - - int packet_frames -- number of frames in a packet, default: 128 - int num_packets -- number of packets in ring buffer, default: 64 - - The sample_rate and num_channels parameters are only hints for the audio - backend, it isn't guaranteed that those are the values used for actual - playback. - - To get the actual parameters, call the following functions after - saudio_setup(): - - int saudio_sample_rate(void) - int saudio_channels(void); - - It's unlikely that the number of channels will be different than requested, - but a different sample rate isn't uncommon. - - (NOTE: there's an yet unsolved issue when an audio backend might switch - to a different sample rate when switching output devices, for instance - plugging in a bluetooth headset, this case is currently not handled in - Sokol Audio). - - You can check if audio initialization was successful with - saudio_isvalid(). If backend initialization failed for some reason - (for instance when there's no audio device in the machine), this - will return false. Not checking for success won't do any harm, all - Sokol Audio function will silently fail when called after initialization - has failed, so apart from missing audio output, nothing bad will happen. - - Before your application exits, you should call - - saudio_shutdown(); - - This stops the audio thread (on Linux, Windows and macOS/iOS) and - properly shuts down the audio backend. - - THE STREAM CALLBACK MODEL - ========================= - To use Sokol Audio in stream-callback-mode, provide a callback function - like this in the saudio_desc struct when calling saudio_setup(): - - void stream_cb(float* buffer, int num_frames, int num_channels) { - ... - } - - Or the alternative version with a user-data argument: - - void stream_userdata_cb(float* buffer, int num_frames, int num_channels, void* user_data) { - my_data_t* my_data = (my_data_t*) user_data; - ... - } - - The job of the callback function is to fill the *buffer* with 32-bit - float sample values. - - To output silence, fill the buffer with zeros: - - void stream_cb(float* buffer, int num_frames, int num_channels) { - const int num_samples = num_frames * num_channels; - for (int i = 0; i < num_samples; i++) { - buffer[i] = 0.0f; - } - } - - For stereo output (num_channels == 2), the samples for the left - and right channel are interleaved: - - void stream_cb(float* buffer, int num_frames, int num_channels) { - assert(2 == num_channels); - for (int i = 0; i < num_frames; i++) { - buffer[2*i + 0] = ...; // left channel - buffer[2*i + 1] = ...; // right channel - } - } - - Please keep in mind that the stream callback function is running in a - separate thread, if you need to share data with the main thread you need - to take care yourself to make the access to the shared data thread-safe! - - THE PUSH MODEL - ============== - To use the push-model for providing audio data, simply don't set (keep - zero-initialized) the stream_cb field in the saudio_desc struct when - calling saudio_setup(). - - To provide sample data with the push model, call the saudio_push() - function at regular intervals (for instance once per frame). You can - call the saudio_expect() function to ask Sokol Audio how much room is - in the ring buffer, but if you provide a continuous stream of data - at the right sample rate, saudio_expect() isn't required (it's a simple - way to sync/throttle your sample generation code with the playback - rate though). - - With saudio_push() you may need to maintain your own intermediate sample - buffer, since pushing individual sample values isn't very efficient. - The following example is from the MOD player sample in - sokol-samples (https://github.com/floooh/sokol-samples): - - const int num_frames = saudio_expect(); - if (num_frames > 0) { - const int num_samples = num_frames * saudio_channels(); - read_samples(flt_buf, num_samples); - saudio_push(flt_buf, num_frames); - } - - Another option is to ignore saudio_expect(), and just push samples as they - are generated in small batches. In this case you *need* to generate the - samples at the right sample rate: - - The following example is taken from the Tiny Emulators project - (https://github.com/floooh/chips-test), this is for mono playback, - so (num_samples == num_frames): - - // tick the sound generator - if (ay38910_tick(&sys->psg)) { - // new sample is ready - sys->sample_buffer[sys->sample_pos++] = sys->psg.sample; - if (sys->sample_pos == sys->num_samples) { - // new sample packet is ready - saudio_push(sys->sample_buffer, sys->num_samples); - sys->sample_pos = 0; - } - } - - THE WEBAUDIO BACKEND - ==================== - The WebAudio backend is currently using a ScriptProcessorNode callback to - feed the sample data into WebAudio. ScriptProcessorNode has been - deprecated for a while because it is running from the main thread, with - the default initialization parameters it works 'pretty well' though. - Ultimately Sokol Audio will use Audio Worklets, but this requires a few - more things to fall into place (Audio Worklets implemented everywhere, - SharedArrayBuffers enabled again, and I need to figure out a 'low-cost' - solution in terms of implementation effort, since Audio Worklets are - a lot more complex than ScriptProcessorNode if the audio data needs to come - from the main thread). - - The WebAudio backend is automatically selected when compiling for - emscripten (__EMSCRIPTEN__ define exists). - - https://developers.google.com/web/updates/2017/12/audio-worklet - https://developers.google.com/web/updates/2018/06/audio-worklet-design-pattern - - "Blob URLs": https://www.html5rocks.com/en/tutorials/workers/basics/ - - Also see: https://blog.paul.cx/post/a-wait-free-spsc-ringbuffer-for-the-web/ - - THE COREAUDIO BACKEND - ===================== - The CoreAudio backend is selected on macOS and iOS (__APPLE__ is defined). - Since the CoreAudio API is implemented in C (not Objective-C) on macOS the - implementation part of Sokol Audio can be included into a C source file. - - However on iOS, Sokol Audio must be compiled as Objective-C due to it's - reliance on the AVAudioSession object. The iOS code path support both - being compiled with or without ARC (Automatic Reference Counting). - - For thread synchronisation, the CoreAudio backend will use the - pthread_mutex_* functions. - - The incoming floating point samples will be directly forwarded to - CoreAudio without further conversion. - - macOS and iOS applications that use Sokol Audio need to link with - the AudioToolbox framework. - - THE WASAPI BACKEND - ================== - The WASAPI backend is automatically selected when compiling on Windows - (_WIN32 is defined). - - For thread synchronisation a Win32 critical section is used. - - WASAPI may use a different size for its own streaming buffer then requested, - so the base latency may be slightly bigger. The current backend implementation - converts the incoming floating point sample values to signed 16-bit - integers. - - The required Windows system DLLs are linked with #pragma comment(lib, ...), - so you shouldn't need to add additional linker libs in the build process - (otherwise this is a bug which should be fixed in sokol_audio.h). - - THE ALSA BACKEND - ================ - The ALSA backend is automatically selected when compiling on Linux - ('linux' is defined). - - For thread synchronisation, the pthread_mutex_* functions are used. - - Samples are directly forwarded to ALSA in 32-bit float format, no - further conversion is taking place. - - You need to link with the 'asound' library, and the - header must be present (usually both are installed with some sort - of ALSA development package). - - - 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); - } - - ... - saudio_setup(&(saudio_desc){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ..., - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_audio.h - itself though, not any allocations in OS libraries. - - Memory allocation will only happen on the same thread where saudio_setup() - was called, so you don't need to worry about thread-safety. - - - 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" - - saudio_setup(&(saudio_desc){ .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. 'saudio' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SAUDIO_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_audio.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-audio like this: - - saudio_setup(&(saudio_desc){ - .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. -*/ -#define SOKOL_AUDIO_INCLUDED (1) -#include // size_t -#include -#include - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_AUDIO_API_DECL) -#define SOKOL_AUDIO_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_AUDIO_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_AUDIO_IMPL) -#define SOKOL_AUDIO_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_AUDIO_API_DECL __declspec(dllimport) -#else -#define SOKOL_AUDIO_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - saudio_log_item - - Log items are defined via X-Macros, and expanded to an - enum 'saudio_log_item', and in debug mode only, - corresponding strings. - - Used as parameter in the logging callback. -*/ -#define _SAUDIO_LOG_ITEMS \ - _SAUDIO_LOGITEM_XMACRO(OK, "Ok") \ - _SAUDIO_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SAUDIO_LOGITEM_XMACRO(ALSA_SND_PCM_OPEN_FAILED, "snd_pcm_open() failed") \ - _SAUDIO_LOGITEM_XMACRO(ALSA_FLOAT_SAMPLES_NOT_SUPPORTED, "floating point sample format not supported") \ - _SAUDIO_LOGITEM_XMACRO(ALSA_REQUESTED_BUFFER_SIZE_NOT_SUPPORTED, "requested buffer size not supported") \ - _SAUDIO_LOGITEM_XMACRO(ALSA_REQUESTED_CHANNEL_COUNT_NOT_SUPPORTED, "requested channel count not supported") \ - _SAUDIO_LOGITEM_XMACRO(ALSA_SND_PCM_HW_PARAMS_SET_RATE_NEAR_FAILED, "snd_pcm_hw_params_set_rate_near() failed") \ - _SAUDIO_LOGITEM_XMACRO(ALSA_SND_PCM_HW_PARAMS_FAILED, "snd_pcm_hw_params() failed") \ - _SAUDIO_LOGITEM_XMACRO(ALSA_PTHREAD_CREATE_FAILED, "pthread_create() failed") \ - _SAUDIO_LOGITEM_XMACRO(WASAPI_CREATE_EVENT_FAILED, "CreateEvent() failed") \ - _SAUDIO_LOGITEM_XMACRO(WASAPI_CREATE_DEVICE_ENUMERATOR_FAILED, "CoCreateInstance() for IMMDeviceEnumerator failed") \ - _SAUDIO_LOGITEM_XMACRO(WASAPI_GET_DEFAULT_AUDIO_ENDPOINT_FAILED, "IMMDeviceEnumerator.GetDefaultAudioEndpoint() failed") \ - _SAUDIO_LOGITEM_XMACRO(WASAPI_DEVICE_ACTIVATE_FAILED, "IMMDevice.Activate() failed") \ - _SAUDIO_LOGITEM_XMACRO(WASAPI_AUDIO_CLIENT_INITIALIZE_FAILED, "IAudioClient.Initialize() failed") \ - _SAUDIO_LOGITEM_XMACRO(WASAPI_AUDIO_CLIENT_GET_BUFFER_SIZE_FAILED, "IAudioClient.GetBufferSize() failed") \ - _SAUDIO_LOGITEM_XMACRO(WASAPI_AUDIO_CLIENT_GET_SERVICE_FAILED, "IAudioClient.GetService() failed") \ - _SAUDIO_LOGITEM_XMACRO(WASAPI_AUDIO_CLIENT_SET_EVENT_HANDLE_FAILED, "IAudioClient.SetEventHandle() failed") \ - _SAUDIO_LOGITEM_XMACRO(WASAPI_CREATE_THREAD_FAILED, "CreateThread() failed") \ - _SAUDIO_LOGITEM_XMACRO(AAUDIO_STREAMBUILDER_OPEN_STREAM_FAILED, "AAudioStreamBuilder_openStream() failed") \ - _SAUDIO_LOGITEM_XMACRO(AAUDIO_PTHREAD_CREATE_FAILED, "pthread_create() failed after AAUDIO_ERROR_DISCONNECTED") \ - _SAUDIO_LOGITEM_XMACRO(AAUDIO_RESTARTING_STREAM_AFTER_ERROR, "restarting AAudio stream after error") \ - _SAUDIO_LOGITEM_XMACRO(USING_AAUDIO_BACKEND, "using AAudio backend") \ - _SAUDIO_LOGITEM_XMACRO(AAUDIO_CREATE_STREAMBUILDER_FAILED, "AAudio_createStreamBuilder() failed") \ - _SAUDIO_LOGITEM_XMACRO(USING_SLES_BACKEND, "using OpenSLES backend") \ - _SAUDIO_LOGITEM_XMACRO(SLES_CREATE_ENGINE_FAILED, "slCreateEngine() failed") \ - _SAUDIO_LOGITEM_XMACRO(SLES_ENGINE_GET_ENGINE_INTERFACE_FAILED, "GetInterface() for SL_IID_ENGINE failed") \ - _SAUDIO_LOGITEM_XMACRO(SLES_CREATE_OUTPUT_MIX_FAILED, "CreateOutputMix() failed") \ - _SAUDIO_LOGITEM_XMACRO(SLES_MIXER_GET_VOLUME_INTERFACE_FAILED, "GetInterface() for SL_IID_VOLUME failed") \ - _SAUDIO_LOGITEM_XMACRO(SLES_ENGINE_CREATE_AUDIO_PLAYER_FAILED, "CreateAudioPlayer() failed") \ - _SAUDIO_LOGITEM_XMACRO(SLES_PLAYER_GET_PLAY_INTERFACE_FAILED, "GetInterface() for SL_IID_PLAY failed") \ - _SAUDIO_LOGITEM_XMACRO(SLES_PLAYER_GET_VOLUME_INTERFACE_FAILED, "GetInterface() for SL_IID_VOLUME failed") \ - _SAUDIO_LOGITEM_XMACRO(SLES_PLAYER_GET_BUFFERQUEUE_INTERFACE_FAILED, "GetInterface() for SL_IID_ANDROIDSIMPLEBUFFERQUEUE failed") \ - _SAUDIO_LOGITEM_XMACRO(COREAUDIO_NEW_OUTPUT_FAILED, "AudioQueueNewOutput() failed") \ - _SAUDIO_LOGITEM_XMACRO(COREAUDIO_ALLOCATE_BUFFER_FAILED, "AudioQueueAllocateBuffer() failed") \ - _SAUDIO_LOGITEM_XMACRO(COREAUDIO_START_FAILED, "AudioQueueStart() failed") \ - _SAUDIO_LOGITEM_XMACRO(BACKEND_BUFFER_SIZE_ISNT_MULTIPLE_OF_PACKET_SIZE, "backend buffer size isn't multiple of packet size") \ - -#define _SAUDIO_LOGITEM_XMACRO(item,msg) SAUDIO_LOGITEM_##item, -typedef enum saudio_log_item { - _SAUDIO_LOG_ITEMS -} saudio_log_item; -#undef _SAUDIO_LOGITEM_XMACRO - -/* - saudio_logger - - Used in saudio_desc to provide a custom logging and error reporting - callback to sokol-audio. -*/ -typedef struct saudio_logger { - void (*func)( - const char* tag, // always "saudio" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SAUDIO_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_audio.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} saudio_logger; - -/* - saudio_allocator - - Used in saudio_desc to provide custom memory-alloc and -free functions - to sokol_audio.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct saudio_allocator { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} saudio_allocator; - -typedef struct saudio_desc { - int sample_rate; // requested sample rate - int num_channels; // number of channels, default: 1 (mono) - int buffer_frames; // number of frames in streaming buffer - int packet_frames; // number of frames in a packet - int num_packets; // number of packets in packet queue - void (*stream_cb)(float* buffer, int num_frames, int num_channels); // optional streaming callback (no user data) - void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data); //... and with user data - void* user_data; // optional user data argument for stream_userdata_cb - saudio_allocator allocator; // optional allocation override functions - saudio_logger logger; // optional logging function (default: NO LOGGING!) -} saudio_desc; - -/* setup sokol-audio */ -SOKOL_AUDIO_API_DECL void saudio_setup(const saudio_desc* desc); -/* shutdown sokol-audio */ -SOKOL_AUDIO_API_DECL void saudio_shutdown(void); -/* true after setup if audio backend was successfully initialized */ -SOKOL_AUDIO_API_DECL bool saudio_isvalid(void); -/* return the saudio_desc.user_data pointer */ -SOKOL_AUDIO_API_DECL void* saudio_userdata(void); -/* return a copy of the original saudio_desc struct */ -SOKOL_AUDIO_API_DECL saudio_desc saudio_query_desc(void); -/* actual sample rate */ -SOKOL_AUDIO_API_DECL int saudio_sample_rate(void); -/* return actual backend buffer size in number of frames */ -SOKOL_AUDIO_API_DECL int saudio_buffer_frames(void); -/* actual number of channels */ -SOKOL_AUDIO_API_DECL int saudio_channels(void); -/* return true if audio context is currently suspended (only in WebAudio backend, all other backends return false) */ -SOKOL_AUDIO_API_DECL bool saudio_suspended(void); -/* get current number of frames to fill packet queue */ -SOKOL_AUDIO_API_DECL int saudio_expect(void); -/* push sample frames from main thread, returns number of frames actually pushed */ -SOKOL_AUDIO_API_DECL int saudio_push(const float* frames, int num_frames); - -#ifdef __cplusplus -} /* extern "C" */ - -/* reference-based equivalents for c++ */ -inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc); } - -#endif -#endif // SOKOL_AUDIO_INCLUDED - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_AUDIO_IMPL -#define SOKOL_AUDIO_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use saudio_desc.allocator to override memory allocation functions" -#endif - -#include // alloc, free -#include // memset, memcpy -#include // size_t - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -#ifndef _SOKOL_UNUSED - #define _SOKOL_UNUSED(x) (void)(x) -#endif - -// platform detection defines -#if defined(SOKOL_DUMMY_BACKEND) - // nothing -#elif defined(__APPLE__) - #define _SAUDIO_APPLE (1) - #include - #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE - #define _SAUDIO_IOS (1) - #else - #define _SAUDIO_MACOS (1) - #endif -#elif defined(__EMSCRIPTEN__) - #define _SAUDIO_EMSCRIPTEN (1) -#elif defined(_WIN32) - #define _SAUDIO_WINDOWS (1) - #include - #if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) - #error "sokol_audio.h no longer supports UWP" - #endif -#elif defined(__ANDROID__) - #define _SAUDIO_ANDROID (1) - #if !defined(SAUDIO_ANDROID_SLES) && !defined(SAUDIO_ANDROID_AAUDIO) - #define SAUDIO_ANDROID_AAUDIO (1) - #endif -#elif defined(__linux__) || defined(__unix__) - #define _SAUDIO_LINUX (1) -#else -#error "sokol_audio.h: Unknown platform" -#endif - -// platform-specific headers and definitions -#if defined(SOKOL_DUMMY_BACKEND) - #define _SAUDIO_NOTHREADS (1) -#elif defined(_SAUDIO_WINDOWS) - #define _SAUDIO_WINTHREADS (1) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - #ifndef NOMINMAX - #define NOMINMAX - #endif - #include - #include - #pragma comment (lib, "kernel32") - #pragma comment (lib, "ole32") - #ifndef CINTERFACE - #define CINTERFACE - #endif - #ifndef COBJMACROS - #define COBJMACROS - #endif - #ifndef CONST_VTABLE - #define CONST_VTABLE - #endif - #include - #include - static const IID _saudio_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32, {0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2} }; - static const IID _saudio_IID_IMMDeviceEnumerator = { 0xa95664d2, 0x9614, 0x4f35, {0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6} }; - static const CLSID _saudio_CLSID_IMMDeviceEnumerator = { 0xbcde0395, 0xe52f, 0x467c, {0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e} }; - static const IID _saudio_IID_IAudioRenderClient = { 0xf294acfc, 0x3146, 0x4483, {0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2} }; - static const IID _saudio_IID_Devinterface_Audio_Render = { 0xe6327cad, 0xdcec, 0x4949, {0xae, 0x8a, 0x99, 0x1e, 0x97, 0x6a, 0x79, 0xd2} }; - static const IID _saudio_IID_IActivateAudioInterface_Completion_Handler = { 0x94ea2b94, 0xe9cc, 0x49e0, {0xc0, 0xff, 0xee, 0x64, 0xca, 0x8f, 0x5b, 0x90} }; - static const GUID _saudio_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} }; - #if defined(__cplusplus) - #define _SOKOL_AUDIO_WIN32COM_ID(x) (x) - #else - #define _SOKOL_AUDIO_WIN32COM_ID(x) (&x) - #endif - /* fix for Visual Studio 2015 SDKs */ - #ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM - #define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000 - #endif - #ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY - #define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000 - #endif - #ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable:4505) /* unreferenced local function has been removed */ - #endif -#elif defined(_SAUDIO_APPLE) - #define _SAUDIO_PTHREADS (1) - #include - #if defined(_SAUDIO_IOS) - // always use system headers on iOS (for now at least) - #if !defined(SAUDIO_OSX_USE_SYSTEM_HEADERS) - #define SAUDIO_OSX_USE_SYSTEM_HEADERS (1) - #endif - #if !defined(__cplusplus) - #if __has_feature(objc_arc) && !__has_feature(objc_arc_fields) - #error "sokol_audio.h on iOS requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)" - #endif - #endif - #include - #include - #else - #if defined(SAUDIO_OSX_USE_SYSTEM_HEADERS) - #include - #endif - #endif -#elif defined(_SAUDIO_ANDROID) - #define _SAUDIO_PTHREADS (1) - #include - #if defined(SAUDIO_ANDROID_SLES) - #include "SLES/OpenSLES_Android.h" - #elif defined(SAUDIO_ANDROID_AAUDIO) - #include "aaudio/AAudio.h" - #endif -#elif defined(_SAUDIO_LINUX) - #if !defined(__FreeBSD__) - #include - #endif - #define _SAUDIO_PTHREADS (1) - #include - #define ALSA_PCM_NEW_HW_PARAMS_API - #include -#elif defined(__EMSCRIPTEN__) - #define _SAUDIO_NOTHREADS (1) - #include -#endif - -#define _saudio_def(val, def) (((val) == 0) ? (def) : (val)) -#define _saudio_def_flt(val, def) (((val) == 0.0f) ? (def) : (val)) - -#define _SAUDIO_DEFAULT_SAMPLE_RATE (44100) -#define _SAUDIO_DEFAULT_BUFFER_FRAMES (2048) -#define _SAUDIO_DEFAULT_PACKET_FRAMES (128) -#define _SAUDIO_DEFAULT_NUM_PACKETS ((_SAUDIO_DEFAULT_BUFFER_FRAMES/_SAUDIO_DEFAULT_PACKET_FRAMES)*4) - -#ifndef SAUDIO_RING_MAX_SLOTS -#define SAUDIO_RING_MAX_SLOTS (1024) -#endif - -// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██████ ██ ██ ██ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██████ ██████ ██ ███████ -// -// >>structs -#if defined(_SAUDIO_PTHREADS) - -typedef struct { - pthread_mutex_t mutex; -} _saudio_mutex_t; - -#elif defined(_SAUDIO_WINTHREADS) - -typedef struct { - CRITICAL_SECTION critsec; -} _saudio_mutex_t; - -#elif defined(_SAUDIO_NOTHREADS) - -typedef struct { - int dummy_mutex; -} _saudio_mutex_t; - -#endif - -#if defined(SOKOL_DUMMY_BACKEND) - -typedef struct { - int dummy; -} _saudio_dummy_backend_t; - -#elif defined(_SAUDIO_APPLE) - -#if defined(SAUDIO_OSX_USE_SYSTEM_HEADERS) - -typedef AudioQueueRef _saudio_AudioQueueRef; -typedef AudioQueueBufferRef _saudio_AudioQueueBufferRef; -typedef AudioStreamBasicDescription _saudio_AudioStreamBasicDescription; -typedef OSStatus _saudio_OSStatus; - -#define _saudio_kAudioFormatLinearPCM (kAudioFormatLinearPCM) -#define _saudio_kLinearPCMFormatFlagIsFloat (kLinearPCMFormatFlagIsFloat) -#define _saudio_kAudioFormatFlagIsPacked (kAudioFormatFlagIsPacked) - -#else -#ifdef __cplusplus -extern "C" { -#endif - -// embedded AudioToolbox declarations -typedef uint32_t _saudio_AudioFormatID; -typedef uint32_t _saudio_AudioFormatFlags; -typedef int32_t _saudio_OSStatus; -typedef uint32_t _saudio_SMPTETimeType; -typedef uint32_t _saudio_SMPTETimeFlags; -typedef uint32_t _saudio_AudioTimeStampFlags; -typedef void* _saudio_CFRunLoopRef; -typedef void* _saudio_CFStringRef; -typedef void* _saudio_AudioQueueRef; - -#define _saudio_kAudioFormatLinearPCM ('lpcm') -#define _saudio_kLinearPCMFormatFlagIsFloat (1U << 0) -#define _saudio_kAudioFormatFlagIsPacked (1U << 3) - -typedef struct _saudio_AudioStreamBasicDescription { - double mSampleRate; - _saudio_AudioFormatID mFormatID; - _saudio_AudioFormatFlags mFormatFlags; - uint32_t mBytesPerPacket; - uint32_t mFramesPerPacket; - uint32_t mBytesPerFrame; - uint32_t mChannelsPerFrame; - uint32_t mBitsPerChannel; - uint32_t mReserved; -} _saudio_AudioStreamBasicDescription; - -typedef struct _saudio_AudioStreamPacketDescription { - int64_t mStartOffset; - uint32_t mVariableFramesInPacket; - uint32_t mDataByteSize; -} _saudio_AudioStreamPacketDescription; - -typedef struct _saudio_SMPTETime { - int16_t mSubframes; - int16_t mSubframeDivisor; - uint32_t mCounter; - _saudio_SMPTETimeType mType; - _saudio_SMPTETimeFlags mFlags; - int16_t mHours; - int16_t mMinutes; - int16_t mSeconds; - int16_t mFrames; -} _saudio_SMPTETime; - -typedef struct _saudio_AudioTimeStamp { - double mSampleTime; - uint64_t mHostTime; - double mRateScalar; - uint64_t mWordClockTime; - _saudio_SMPTETime mSMPTETime; - _saudio_AudioTimeStampFlags mFlags; - uint32_t mReserved; -} _saudio_AudioTimeStamp; - -typedef struct _saudio_AudioQueueBuffer { - const uint32_t mAudioDataBytesCapacity; - void* const mAudioData; - uint32_t mAudioDataByteSize; - void * mUserData; - const uint32_t mPacketDescriptionCapacity; - _saudio_AudioStreamPacketDescription* const mPacketDescriptions; - uint32_t mPacketDescriptionCount; -} _saudio_AudioQueueBuffer; -typedef _saudio_AudioQueueBuffer* _saudio_AudioQueueBufferRef; - -typedef void (*_saudio_AudioQueueOutputCallback)(void* user_data, _saudio_AudioQueueRef inAQ, _saudio_AudioQueueBufferRef inBuffer); - -extern _saudio_OSStatus AudioQueueNewOutput(const _saudio_AudioStreamBasicDescription* inFormat, _saudio_AudioQueueOutputCallback inCallbackProc, void* inUserData, _saudio_CFRunLoopRef inCallbackRunLoop, _saudio_CFStringRef inCallbackRunLoopMode, uint32_t inFlags, _saudio_AudioQueueRef* outAQ); -extern _saudio_OSStatus AudioQueueDispose(_saudio_AudioQueueRef inAQ, bool inImmediate); -extern _saudio_OSStatus AudioQueueAllocateBuffer(_saudio_AudioQueueRef inAQ, uint32_t inBufferByteSize, _saudio_AudioQueueBufferRef* outBuffer); -extern _saudio_OSStatus AudioQueueEnqueueBuffer(_saudio_AudioQueueRef inAQ, _saudio_AudioQueueBufferRef inBuffer, uint32_t inNumPacketDescs, const _saudio_AudioStreamPacketDescription* inPacketDescs); -extern _saudio_OSStatus AudioQueueStart(_saudio_AudioQueueRef inAQ, const _saudio_AudioTimeStamp * inStartTime); -extern _saudio_OSStatus AudioQueueStop(_saudio_AudioQueueRef inAQ, bool inImmediate); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // SAUDIO_OSX_USE_SYSTEM_HEADERS - -typedef struct { - _saudio_AudioQueueRef ca_audio_queue; - #if defined(_SAUDIO_IOS) - id ca_interruption_handler; - #endif -} _saudio_apple_backend_t; - -#elif defined(_SAUDIO_LINUX) - -typedef struct { - snd_pcm_t* device; - float* buffer; - int buffer_byte_size; - int buffer_frames; - pthread_t thread; - bool thread_stop; -} _saudio_alsa_backend_t; - -#elif defined(SAUDIO_ANDROID_SLES) - -#define SAUDIO_SLES_NUM_BUFFERS (2) - -typedef struct { - pthread_mutex_t mutex; - pthread_cond_t cond; - int count; -} _saudio_sles_semaphore_t; - -typedef struct { - SLObjectItf engine_obj; - SLEngineItf engine; - SLObjectItf output_mix_obj; - SLVolumeItf output_mix_vol; - SLDataLocator_OutputMix out_locator; - SLDataSink dst_data_sink; - SLObjectItf player_obj; - SLPlayItf player; - SLVolumeItf player_vol; - SLAndroidSimpleBufferQueueItf player_buffer_queue; - - int16_t* output_buffers[SAUDIO_SLES_NUM_BUFFERS]; - float* src_buffer; - int active_buffer; - _saudio_sles_semaphore_t buffer_sem; - pthread_t thread; - volatile int thread_stop; - SLDataLocator_AndroidSimpleBufferQueue in_locator; -} _saudio_sles_backend_t; - -#elif defined(SAUDIO_ANDROID_AAUDIO) - -typedef struct { - AAudioStreamBuilder* builder; - AAudioStream* stream; - pthread_t thread; - pthread_mutex_t mutex; -} _saudio_aaudio_backend_t; - -#elif defined(_SAUDIO_WINDOWS) - -typedef struct { - HANDLE thread_handle; - HANDLE buffer_end_event; - bool stop; - UINT32 dst_buffer_frames; - int src_buffer_frames; - int src_buffer_byte_size; - int src_buffer_pos; - float* src_buffer; -} _saudio_wasapi_thread_data_t; - -typedef struct { - IMMDeviceEnumerator* device_enumerator; - IMMDevice* device; - IAudioClient* audio_client; - IAudioRenderClient* render_client; - _saudio_wasapi_thread_data_t thread; -} _saudio_wasapi_backend_t; - -#elif defined(_SAUDIO_EMSCRIPTEN) - -typedef struct { - uint8_t* buffer; -} _saudio_web_backend_t; - -#else -#error "unknown platform" -#endif - -#if defined(SOKOL_DUMMY_BACKEND) -typedef _saudio_dummy_backend_t _saudio_backend_t; -#elif defined(_SAUDIO_APPLE) -typedef _saudio_apple_backend_t _saudio_backend_t; -#elif defined(_SAUDIO_EMSCRIPTEN) -typedef _saudio_web_backend_t _saudio_backend_t; -#elif defined(_SAUDIO_WINDOWS) -typedef _saudio_wasapi_backend_t _saudio_backend_t; -#elif defined(SAUDIO_ANDROID_SLES) -typedef _saudio_sles_backend_t _saudio_backend_t; -#elif defined(SAUDIO_ANDROID_AAUDIO) -typedef _saudio_aaudio_backend_t _saudio_backend_t; -#elif defined(_SAUDIO_LINUX) -typedef _saudio_alsa_backend_t _saudio_backend_t; -#endif - -/* a ringbuffer structure */ -typedef struct { - int head; // next slot to write to - int tail; // next slot to read from - int num; // number of slots in queue - int queue[SAUDIO_RING_MAX_SLOTS]; -} _saudio_ring_t; - -/* a packet FIFO structure */ -typedef struct { - bool valid; - int packet_size; /* size of a single packets in bytes(!) */ - int num_packets; /* number of packet in fifo */ - uint8_t* base_ptr; /* packet memory chunk base pointer (dynamically allocated) */ - int cur_packet; /* current write-packet */ - int cur_offset; /* current byte-offset into current write packet */ - _saudio_mutex_t mutex; /* mutex for thread-safe access */ - _saudio_ring_t read_queue; /* buffers with data, ready to be streamed */ - _saudio_ring_t write_queue; /* empty buffers, ready to be pushed to */ -} _saudio_fifo_t; - -/* sokol-audio state */ -typedef struct { - bool valid; - bool setup_called; - void (*stream_cb)(float* buffer, int num_frames, int num_channels); - void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data); - void* user_data; - int sample_rate; /* sample rate */ - int buffer_frames; /* number of frames in streaming buffer */ - int bytes_per_frame; /* filled by backend */ - int packet_frames; /* number of frames in a packet */ - int num_packets; /* number of packets in packet queue */ - int num_channels; /* actual number of channels */ - saudio_desc desc; - _saudio_fifo_t fifo; - _saudio_backend_t backend; -} _saudio_state_t; - -_SOKOL_PRIVATE _saudio_state_t _saudio; - -_SOKOL_PRIVATE bool _saudio_has_callback(void) { - return (_saudio.stream_cb || _saudio.stream_userdata_cb); -} - -_SOKOL_PRIVATE void _saudio_stream_callback(float* buffer, int num_frames, int num_channels) { - if (_saudio.stream_cb) { - _saudio.stream_cb(buffer, num_frames, num_channels); - } - else if (_saudio.stream_userdata_cb) { - _saudio.stream_userdata_cb(buffer, num_frames, num_channels, _saudio.user_data); - } -} - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SAUDIO_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _saudio_log_messages[] = { - _SAUDIO_LOG_ITEMS -}; -#undef _SAUDIO_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SAUDIO_PANIC(code) _saudio_log(SAUDIO_LOGITEM_ ##code, 0, __LINE__) -#define _SAUDIO_ERROR(code) _saudio_log(SAUDIO_LOGITEM_ ##code, 1, __LINE__) -#define _SAUDIO_WARN(code) _saudio_log(SAUDIO_LOGITEM_ ##code, 2, __LINE__) -#define _SAUDIO_INFO(code) _saudio_log(SAUDIO_LOGITEM_ ##code, 3, __LINE__) - -static void _saudio_log(saudio_log_item log_item, uint32_t log_level, uint32_t line_nr) { - if (_saudio.desc.logger.func) { - #if defined(SOKOL_DEBUG) - const char* filename = __FILE__; - const char* message = _saudio_log_messages[log_item]; - #else - const char* filename = 0; - const char* message = 0; - #endif - _saudio.desc.logger.func("saudio", log_level, log_item, message, line_nr, filename, _saudio.desc.logger.user_data); - } - else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -_SOKOL_PRIVATE void _saudio_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -_SOKOL_PRIVATE void* _saudio_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_saudio.desc.allocator.alloc_fn) { - ptr = _saudio.desc.allocator.alloc_fn(size, _saudio.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SAUDIO_PANIC(MALLOC_FAILED); - } - return ptr; -} - -_SOKOL_PRIVATE void* _saudio_malloc_clear(size_t size) { - void* ptr = _saudio_malloc(size); - _saudio_clear(ptr, size); - return ptr; -} - -_SOKOL_PRIVATE void _saudio_free(void* ptr) { - if (_saudio.desc.allocator.free_fn) { - _saudio.desc.allocator.free_fn(ptr, _saudio.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ███ ███ ██ ██ ████████ ███████ ██ ██ -// ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ ██ ██ ██ █████ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██████ ██ ███████ ██ ██ -// -// >>mutex -#if defined(_SAUDIO_NOTHREADS) - -_SOKOL_PRIVATE void _saudio_mutex_init(_saudio_mutex_t* m) { (void)m; } -_SOKOL_PRIVATE void _saudio_mutex_destroy(_saudio_mutex_t* m) { (void)m; } -_SOKOL_PRIVATE void _saudio_mutex_lock(_saudio_mutex_t* m) { (void)m; } -_SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) { (void)m; } - -#elif defined(_SAUDIO_PTHREADS) - -_SOKOL_PRIVATE void _saudio_mutex_init(_saudio_mutex_t* m) { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutex_init(&m->mutex, &attr); -} - -_SOKOL_PRIVATE void _saudio_mutex_destroy(_saudio_mutex_t* m) { - pthread_mutex_destroy(&m->mutex); -} - -_SOKOL_PRIVATE void _saudio_mutex_lock(_saudio_mutex_t* m) { - pthread_mutex_lock(&m->mutex); -} - -_SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) { - pthread_mutex_unlock(&m->mutex); -} - -#elif defined(_SAUDIO_WINTHREADS) - -_SOKOL_PRIVATE void _saudio_mutex_init(_saudio_mutex_t* m) { - InitializeCriticalSection(&m->critsec); -} - -_SOKOL_PRIVATE void _saudio_mutex_destroy(_saudio_mutex_t* m) { - DeleteCriticalSection(&m->critsec); -} - -_SOKOL_PRIVATE void _saudio_mutex_lock(_saudio_mutex_t* m) { - EnterCriticalSection(&m->critsec); -} - -_SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) { - LeaveCriticalSection(&m->critsec); -} -#else -#error "sokol_audio.h: unknown platform!" -#endif - -// ██████ ██ ███ ██ ██████ ██████ ██ ██ ███████ ███████ ███████ ██████ -// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ ███ ██████ ██ ██ █████ █████ █████ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ████ ██████ ██████ ██████ ██ ██ ███████ ██ ██ -// -// >>ringbuffer -_SOKOL_PRIVATE int _saudio_ring_idx(_saudio_ring_t* ring, int i) { - return (i % ring->num); -} - -_SOKOL_PRIVATE void _saudio_ring_init(_saudio_ring_t* ring, int num_slots) { - SOKOL_ASSERT((num_slots + 1) <= SAUDIO_RING_MAX_SLOTS); - ring->head = 0; - ring->tail = 0; - /* one slot reserved to detect 'full' vs 'empty' */ - ring->num = num_slots + 1; -} - -_SOKOL_PRIVATE bool _saudio_ring_full(_saudio_ring_t* ring) { - return _saudio_ring_idx(ring, ring->head + 1) == ring->tail; -} - -_SOKOL_PRIVATE bool _saudio_ring_empty(_saudio_ring_t* ring) { - return ring->head == ring->tail; -} - -_SOKOL_PRIVATE int _saudio_ring_count(_saudio_ring_t* ring) { - int count; - if (ring->head >= ring->tail) { - count = ring->head - ring->tail; - } - else { - count = (ring->head + ring->num) - ring->tail; - } - SOKOL_ASSERT(count < ring->num); - return count; -} - -_SOKOL_PRIVATE void _saudio_ring_enqueue(_saudio_ring_t* ring, int val) { - SOKOL_ASSERT(!_saudio_ring_full(ring)); - ring->queue[ring->head] = val; - ring->head = _saudio_ring_idx(ring, ring->head + 1); -} - -_SOKOL_PRIVATE int _saudio_ring_dequeue(_saudio_ring_t* ring) { - SOKOL_ASSERT(!_saudio_ring_empty(ring)); - int val = ring->queue[ring->tail]; - ring->tail = _saudio_ring_idx(ring, ring->tail + 1); - return val; -} - -// ███████ ██ ███████ ██████ -// ██ ██ ██ ██ ██ -// █████ ██ █████ ██ ██ -// ██ ██ ██ ██ ██ -// ██ ██ ██ ██████ -// -// >>fifo -_SOKOL_PRIVATE void _saudio_fifo_init_mutex(_saudio_fifo_t* fifo) { - /* this must be called before initializing both the backend and the fifo itself! */ - _saudio_mutex_init(&fifo->mutex); -} - -_SOKOL_PRIVATE void _saudio_fifo_destroy_mutex(_saudio_fifo_t* fifo) { - _saudio_mutex_destroy(&fifo->mutex); -} - -_SOKOL_PRIVATE void _saudio_fifo_init(_saudio_fifo_t* fifo, int packet_size, int num_packets) { - /* NOTE: there's a chicken-egg situation during the init phase where the - streaming thread must be started before the fifo is actually initialized, - thus the fifo init must already be protected from access by the fifo_read() func. - */ - _saudio_mutex_lock(&fifo->mutex); - SOKOL_ASSERT((packet_size > 0) && (num_packets > 0)); - fifo->packet_size = packet_size; - fifo->num_packets = num_packets; - fifo->base_ptr = (uint8_t*) _saudio_malloc((size_t)(packet_size * num_packets)); - fifo->cur_packet = -1; - fifo->cur_offset = 0; - _saudio_ring_init(&fifo->read_queue, num_packets); - _saudio_ring_init(&fifo->write_queue, num_packets); - for (int i = 0; i < num_packets; i++) { - _saudio_ring_enqueue(&fifo->write_queue, i); - } - SOKOL_ASSERT(_saudio_ring_full(&fifo->write_queue)); - SOKOL_ASSERT(_saudio_ring_count(&fifo->write_queue) == num_packets); - SOKOL_ASSERT(_saudio_ring_empty(&fifo->read_queue)); - SOKOL_ASSERT(_saudio_ring_count(&fifo->read_queue) == 0); - fifo->valid = true; - _saudio_mutex_unlock(&fifo->mutex); -} - -_SOKOL_PRIVATE void _saudio_fifo_shutdown(_saudio_fifo_t* fifo) { - SOKOL_ASSERT(fifo->base_ptr); - _saudio_free(fifo->base_ptr); - fifo->base_ptr = 0; - fifo->valid = false; -} - -_SOKOL_PRIVATE int _saudio_fifo_writable_bytes(_saudio_fifo_t* fifo) { - _saudio_mutex_lock(&fifo->mutex); - int num_bytes = (_saudio_ring_count(&fifo->write_queue) * fifo->packet_size); - if (fifo->cur_packet != -1) { - num_bytes += fifo->packet_size - fifo->cur_offset; - } - _saudio_mutex_unlock(&fifo->mutex); - SOKOL_ASSERT((num_bytes >= 0) && (num_bytes <= (fifo->num_packets * fifo->packet_size))); - return num_bytes; -} - -/* write new data to the write queue, this is called from main thread */ -_SOKOL_PRIVATE int _saudio_fifo_write(_saudio_fifo_t* fifo, const uint8_t* ptr, int num_bytes) { - /* returns the number of bytes written, this will be smaller then requested - if the write queue runs full - */ - int all_to_copy = num_bytes; - while (all_to_copy > 0) { - /* need to grab a new packet? */ - if (fifo->cur_packet == -1) { - _saudio_mutex_lock(&fifo->mutex); - if (!_saudio_ring_empty(&fifo->write_queue)) { - fifo->cur_packet = _saudio_ring_dequeue(&fifo->write_queue); - } - _saudio_mutex_unlock(&fifo->mutex); - SOKOL_ASSERT(fifo->cur_offset == 0); - } - /* append data to current write packet */ - if (fifo->cur_packet != -1) { - int to_copy = all_to_copy; - const int max_copy = fifo->packet_size - fifo->cur_offset; - if (to_copy > max_copy) { - to_copy = max_copy; - } - uint8_t* dst = fifo->base_ptr + fifo->cur_packet * fifo->packet_size + fifo->cur_offset; - memcpy(dst, ptr, (size_t)to_copy); - ptr += to_copy; - fifo->cur_offset += to_copy; - all_to_copy -= to_copy; - SOKOL_ASSERT(fifo->cur_offset <= fifo->packet_size); - SOKOL_ASSERT(all_to_copy >= 0); - } - else { - /* early out if we're starving */ - int bytes_copied = num_bytes - all_to_copy; - SOKOL_ASSERT((bytes_copied >= 0) && (bytes_copied < num_bytes)); - return bytes_copied; - } - /* if write packet is full, push to read queue */ - if (fifo->cur_offset == fifo->packet_size) { - _saudio_mutex_lock(&fifo->mutex); - _saudio_ring_enqueue(&fifo->read_queue, fifo->cur_packet); - _saudio_mutex_unlock(&fifo->mutex); - fifo->cur_packet = -1; - fifo->cur_offset = 0; - } - } - SOKOL_ASSERT(all_to_copy == 0); - return num_bytes; -} - -/* read queued data, this is called form the stream callback (maybe separate thread) */ -_SOKOL_PRIVATE int _saudio_fifo_read(_saudio_fifo_t* fifo, uint8_t* ptr, int num_bytes) { - /* NOTE: fifo_read might be called before the fifo is properly initialized */ - _saudio_mutex_lock(&fifo->mutex); - int num_bytes_copied = 0; - if (fifo->valid) { - SOKOL_ASSERT(0 == (num_bytes % fifo->packet_size)); - SOKOL_ASSERT(num_bytes <= (fifo->packet_size * fifo->num_packets)); - const int num_packets_needed = num_bytes / fifo->packet_size; - uint8_t* dst = ptr; - /* either pull a full buffer worth of data, or nothing */ - if (_saudio_ring_count(&fifo->read_queue) >= num_packets_needed) { - for (int i = 0; i < num_packets_needed; i++) { - int packet_index = _saudio_ring_dequeue(&fifo->read_queue); - _saudio_ring_enqueue(&fifo->write_queue, packet_index); - const uint8_t* src = fifo->base_ptr + packet_index * fifo->packet_size; - memcpy(dst, src, (size_t)fifo->packet_size); - dst += fifo->packet_size; - num_bytes_copied += fifo->packet_size; - } - SOKOL_ASSERT(num_bytes == num_bytes_copied); - } - } - _saudio_mutex_unlock(&fifo->mutex); - return num_bytes_copied; -} - -// ██████ ██ ██ ███ ███ ███ ███ ██ ██ -// ██ ██ ██ ██ ████ ████ ████ ████ ██ ██ -// ██ ██ ██ ██ ██ ████ ██ ██ ████ ██ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██ ██ ██ ██ ██ -// -// >>dummy -#if defined(SOKOL_DUMMY_BACKEND) -_SOKOL_PRIVATE bool _saudio_dummy_backend_init(void) { - _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float); - return true; -}; -_SOKOL_PRIVATE void _saudio_dummy_backend_shutdown(void) { }; - -// █████ ██ ███████ █████ -// ██ ██ ██ ██ ██ ██ -// ███████ ██ ███████ ███████ -// ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ███████ ██ ██ -// -// >>alsa -#elif defined(_SAUDIO_LINUX) - -/* the streaming callback runs in a separate thread */ -_SOKOL_PRIVATE void* _saudio_alsa_cb(void* param) { - _SOKOL_UNUSED(param); - while (!_saudio.backend.thread_stop) { - /* snd_pcm_writei() will be blocking until it needs data */ - int write_res = snd_pcm_writei(_saudio.backend.device, _saudio.backend.buffer, (snd_pcm_uframes_t)_saudio.backend.buffer_frames); - if (write_res < 0) { - /* underrun occurred */ - snd_pcm_prepare(_saudio.backend.device); - } - else { - /* fill the streaming buffer with new data */ - if (_saudio_has_callback()) { - _saudio_stream_callback(_saudio.backend.buffer, _saudio.backend.buffer_frames, _saudio.num_channels); - } - else { - if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.buffer, _saudio.backend.buffer_byte_size)) { - /* not enough read data available, fill the entire buffer with silence */ - _saudio_clear(_saudio.backend.buffer, (size_t)_saudio.backend.buffer_byte_size); - } - } - } - } - return 0; -} - -_SOKOL_PRIVATE bool _saudio_alsa_backend_init(void) { - int dir; uint32_t rate; - int rc = snd_pcm_open(&_saudio.backend.device, "default", SND_PCM_STREAM_PLAYBACK, 0); - if (rc < 0) { - _SAUDIO_ERROR(ALSA_SND_PCM_OPEN_FAILED); - return false; - } - - /* configuration works by restricting the 'configuration space' step - by step, we require all parameters except the sample rate to - match perfectly - */ - snd_pcm_hw_params_t* params = 0; - snd_pcm_hw_params_alloca(¶ms); - snd_pcm_hw_params_any(_saudio.backend.device, params); - snd_pcm_hw_params_set_access(_saudio.backend.device, params, SND_PCM_ACCESS_RW_INTERLEAVED); - if (0 > snd_pcm_hw_params_set_format(_saudio.backend.device, params, SND_PCM_FORMAT_FLOAT_LE)) { - _SAUDIO_ERROR(ALSA_FLOAT_SAMPLES_NOT_SUPPORTED); - goto error; - } - if (0 > snd_pcm_hw_params_set_buffer_size(_saudio.backend.device, params, (snd_pcm_uframes_t)_saudio.buffer_frames)) { - _SAUDIO_ERROR(ALSA_REQUESTED_BUFFER_SIZE_NOT_SUPPORTED); - goto error; - } - if (0 > snd_pcm_hw_params_set_channels(_saudio.backend.device, params, (uint32_t)_saudio.num_channels)) { - _SAUDIO_ERROR(ALSA_REQUESTED_CHANNEL_COUNT_NOT_SUPPORTED); - goto error; - } - /* let ALSA pick a nearby sampling rate */ - rate = (uint32_t) _saudio.sample_rate; - dir = 0; - if (0 > snd_pcm_hw_params_set_rate_near(_saudio.backend.device, params, &rate, &dir)) { - _SAUDIO_ERROR(ALSA_SND_PCM_HW_PARAMS_SET_RATE_NEAR_FAILED); - goto error; - } - if (0 > snd_pcm_hw_params(_saudio.backend.device, params)) { - _SAUDIO_ERROR(ALSA_SND_PCM_HW_PARAMS_FAILED); - goto error; - } - - /* read back actual sample rate and channels */ - _saudio.sample_rate = (int)rate; - _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float); - - /* allocate the streaming buffer */ - _saudio.backend.buffer_byte_size = _saudio.buffer_frames * _saudio.bytes_per_frame; - _saudio.backend.buffer_frames = _saudio.buffer_frames; - _saudio.backend.buffer = (float*) _saudio_malloc_clear((size_t)_saudio.backend.buffer_byte_size); - - /* create the buffer-streaming start thread */ - if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_alsa_cb, 0)) { - _SAUDIO_ERROR(ALSA_PTHREAD_CREATE_FAILED); - goto error; - } - - return true; -error: - if (_saudio.backend.device) { - snd_pcm_close(_saudio.backend.device); - _saudio.backend.device = 0; - } - return false; -}; - -_SOKOL_PRIVATE void _saudio_alsa_backend_shutdown(void) { - SOKOL_ASSERT(_saudio.backend.device); - _saudio.backend.thread_stop = true; - pthread_join(_saudio.backend.thread, 0); - snd_pcm_drain(_saudio.backend.device); - snd_pcm_close(_saudio.backend.device); - _saudio_free(_saudio.backend.buffer); -}; - -// ██ ██ █████ ███████ █████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ █ ██ ███████ ███████ ███████ ██████ ██ -// ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ -// ███ ███ ██ ██ ███████ ██ ██ ██ ██ -// -// >>wasapi -#elif defined(_SAUDIO_WINDOWS) - -/* fill intermediate buffer with new data and reset buffer_pos */ -_SOKOL_PRIVATE void _saudio_wasapi_fill_buffer(void) { - if (_saudio_has_callback()) { - _saudio_stream_callback(_saudio.backend.thread.src_buffer, _saudio.backend.thread.src_buffer_frames, _saudio.num_channels); - } - else { - if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.thread.src_buffer, _saudio.backend.thread.src_buffer_byte_size)) { - /* not enough read data available, fill the entire buffer with silence */ - _saudio_clear(_saudio.backend.thread.src_buffer, (size_t)_saudio.backend.thread.src_buffer_byte_size); - } - } -} - -_SOKOL_PRIVATE int _saudio_wasapi_min(int a, int b) { - return (a < b) ? a : b; -} - -_SOKOL_PRIVATE void _saudio_wasapi_submit_buffer(int num_frames) { - BYTE* wasapi_buffer = 0; - if (FAILED(IAudioRenderClient_GetBuffer(_saudio.backend.render_client, num_frames, &wasapi_buffer))) { - return; - } - SOKOL_ASSERT(wasapi_buffer); - - /* copy samples to WASAPI buffer, refill source buffer if needed */ - int num_remaining_samples = num_frames * _saudio.num_channels; - int buffer_pos = _saudio.backend.thread.src_buffer_pos; - const int buffer_size_in_samples = _saudio.backend.thread.src_buffer_byte_size / (int)sizeof(float); - float* dst = (float*)wasapi_buffer; - const float* dst_end = dst + num_remaining_samples; - _SOKOL_UNUSED(dst_end); // suppress unused warning in release mode - const float* src = _saudio.backend.thread.src_buffer; - - while (num_remaining_samples > 0) { - if (0 == buffer_pos) { - _saudio_wasapi_fill_buffer(); - } - const int samples_to_copy = _saudio_wasapi_min(num_remaining_samples, buffer_size_in_samples - buffer_pos); - SOKOL_ASSERT((buffer_pos + samples_to_copy) <= buffer_size_in_samples); - SOKOL_ASSERT((dst + samples_to_copy) <= dst_end); - memcpy(dst, &src[buffer_pos], (size_t)samples_to_copy * sizeof(float)); - num_remaining_samples -= samples_to_copy; - SOKOL_ASSERT(num_remaining_samples >= 0); - buffer_pos += samples_to_copy; - dst += samples_to_copy; - - SOKOL_ASSERT(buffer_pos <= buffer_size_in_samples); - if (buffer_pos == buffer_size_in_samples) { - buffer_pos = 0; - } - } - _saudio.backend.thread.src_buffer_pos = buffer_pos; - IAudioRenderClient_ReleaseBuffer(_saudio.backend.render_client, num_frames, 0); -} - -_SOKOL_PRIVATE DWORD WINAPI _saudio_wasapi_thread_fn(LPVOID param) { - (void)param; - _saudio_wasapi_submit_buffer(_saudio.backend.thread.src_buffer_frames); - IAudioClient_Start(_saudio.backend.audio_client); - while (!_saudio.backend.thread.stop) { - WaitForSingleObject(_saudio.backend.thread.buffer_end_event, INFINITE); - UINT32 padding = 0; - if (FAILED(IAudioClient_GetCurrentPadding(_saudio.backend.audio_client, &padding))) { - continue; - } - SOKOL_ASSERT(_saudio.backend.thread.dst_buffer_frames >= padding); - int num_frames = (int)_saudio.backend.thread.dst_buffer_frames - (int)padding; - if (num_frames > 0) { - _saudio_wasapi_submit_buffer(num_frames); - } - } - return 0; -} - -_SOKOL_PRIVATE void _saudio_wasapi_release(void) { - if (_saudio.backend.thread.src_buffer) { - _saudio_free(_saudio.backend.thread.src_buffer); - _saudio.backend.thread.src_buffer = 0; - } - if (_saudio.backend.render_client) { - IAudioRenderClient_Release(_saudio.backend.render_client); - _saudio.backend.render_client = 0; - } - if (_saudio.backend.audio_client) { - IAudioClient_Release(_saudio.backend.audio_client); - _saudio.backend.audio_client = 0; - } - if (_saudio.backend.device) { - IMMDevice_Release(_saudio.backend.device); - _saudio.backend.device = 0; - } - if (_saudio.backend.device_enumerator) { - IMMDeviceEnumerator_Release(_saudio.backend.device_enumerator); - _saudio.backend.device_enumerator = 0; - } - if (0 != _saudio.backend.thread.buffer_end_event) { - CloseHandle(_saudio.backend.thread.buffer_end_event); - _saudio.backend.thread.buffer_end_event = 0; - } -} - -_SOKOL_PRIVATE bool _saudio_wasapi_backend_init(void) { - REFERENCE_TIME dur; - /* CoInitializeEx could have been called elsewhere already, in which - case the function returns with S_FALSE (thus it does not make much - sense to check the result) - */ - HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED); - _SOKOL_UNUSED(hr); - _saudio.backend.thread.buffer_end_event = CreateEvent(0, FALSE, FALSE, 0); - if (0 == _saudio.backend.thread.buffer_end_event) { - _SAUDIO_ERROR(WASAPI_CREATE_EVENT_FAILED); - goto error; - } - if (FAILED(CoCreateInstance(_SOKOL_AUDIO_WIN32COM_ID(_saudio_CLSID_IMMDeviceEnumerator), - 0, CLSCTX_ALL, - _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IMMDeviceEnumerator), - (void**)&_saudio.backend.device_enumerator))) - { - _SAUDIO_ERROR(WASAPI_CREATE_DEVICE_ENUMERATOR_FAILED); - goto error; - } - if (FAILED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(_saudio.backend.device_enumerator, - eRender, eConsole, - &_saudio.backend.device))) - { - _SAUDIO_ERROR(WASAPI_GET_DEFAULT_AUDIO_ENDPOINT_FAILED); - goto error; - } - if (FAILED(IMMDevice_Activate(_saudio.backend.device, - _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioClient), - CLSCTX_ALL, 0, - (void**)&_saudio.backend.audio_client))) - { - _SAUDIO_ERROR(WASAPI_DEVICE_ACTIVATE_FAILED); - goto error; - } - - WAVEFORMATEXTENSIBLE fmtex; - _saudio_clear(&fmtex, sizeof(fmtex)); - fmtex.Format.nChannels = (WORD)_saudio.num_channels; - fmtex.Format.nSamplesPerSec = (DWORD)_saudio.sample_rate; - fmtex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - fmtex.Format.wBitsPerSample = 32; - fmtex.Format.nBlockAlign = (fmtex.Format.nChannels * fmtex.Format.wBitsPerSample) / 8; - fmtex.Format.nAvgBytesPerSec = fmtex.Format.nSamplesPerSec * fmtex.Format.nBlockAlign; - fmtex.Format.cbSize = 22; /* WORD + DWORD + GUID */ - fmtex.Samples.wValidBitsPerSample = 32; - if (_saudio.num_channels == 1) { - fmtex.dwChannelMask = SPEAKER_FRONT_CENTER; - } - else { - fmtex.dwChannelMask = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT; - } - fmtex.SubFormat = _saudio_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - dur = (REFERENCE_TIME) - (((double)_saudio.buffer_frames) / (((double)_saudio.sample_rate) * (1.0/10000000.0))); - if (FAILED(IAudioClient_Initialize(_saudio.backend.audio_client, - AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK|AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM|AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, - dur, 0, (WAVEFORMATEX*)&fmtex, 0))) - { - _SAUDIO_ERROR(WASAPI_AUDIO_CLIENT_INITIALIZE_FAILED); - goto error; - } - if (FAILED(IAudioClient_GetBufferSize(_saudio.backend.audio_client, &_saudio.backend.thread.dst_buffer_frames))) { - _SAUDIO_ERROR(WASAPI_AUDIO_CLIENT_GET_BUFFER_SIZE_FAILED); - goto error; - } - if (FAILED(IAudioClient_GetService(_saudio.backend.audio_client, - _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioRenderClient), - (void**)&_saudio.backend.render_client))) - { - _SAUDIO_ERROR(WASAPI_AUDIO_CLIENT_GET_SERVICE_FAILED); - goto error; - } - if (FAILED(IAudioClient_SetEventHandle(_saudio.backend.audio_client, _saudio.backend.thread.buffer_end_event))) { - _SAUDIO_ERROR(WASAPI_AUDIO_CLIENT_SET_EVENT_HANDLE_FAILED); - goto error; - } - _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float); - _saudio.backend.thread.src_buffer_frames = _saudio.buffer_frames; - _saudio.backend.thread.src_buffer_byte_size = _saudio.backend.thread.src_buffer_frames * _saudio.bytes_per_frame; - - /* allocate an intermediate buffer for sample format conversion */ - _saudio.backend.thread.src_buffer = (float*) _saudio_malloc((size_t)_saudio.backend.thread.src_buffer_byte_size); - - /* create streaming thread */ - _saudio.backend.thread.thread_handle = CreateThread(NULL, 0, _saudio_wasapi_thread_fn, 0, 0, 0); - if (0 == _saudio.backend.thread.thread_handle) { - _SAUDIO_ERROR(WASAPI_CREATE_THREAD_FAILED); - goto error; - } - return true; -error: - _saudio_wasapi_release(); - return false; -} - -_SOKOL_PRIVATE void _saudio_wasapi_backend_shutdown(void) { - if (_saudio.backend.thread.thread_handle) { - _saudio.backend.thread.stop = true; - SetEvent(_saudio.backend.thread.buffer_end_event); - WaitForSingleObject(_saudio.backend.thread.thread_handle, INFINITE); - CloseHandle(_saudio.backend.thread.thread_handle); - _saudio.backend.thread.thread_handle = 0; - } - if (_saudio.backend.audio_client) { - IAudioClient_Stop(_saudio.backend.audio_client); - } - _saudio_wasapi_release(); - CoUninitialize(); -} - -// ██ ██ ███████ ██████ █████ ██ ██ ██████ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ █ ██ █████ ██████ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███ ███ ███████ ██████ ██ ██ ██████ ██████ ██ ██████ -// -// >>webaudio -#elif defined(_SAUDIO_EMSCRIPTEN) - -#ifdef __cplusplus -extern "C" { -#endif - -EMSCRIPTEN_KEEPALIVE int _saudio_emsc_pull(int num_frames) { - SOKOL_ASSERT(_saudio.backend.buffer); - if (num_frames == _saudio.buffer_frames) { - if (_saudio_has_callback()) { - _saudio_stream_callback((float*)_saudio.backend.buffer, num_frames, _saudio.num_channels); - } - else { - const int num_bytes = num_frames * _saudio.bytes_per_frame; - if (0 == _saudio_fifo_read(&_saudio.fifo, _saudio.backend.buffer, num_bytes)) { - /* not enough read data available, fill the entire buffer with silence */ - _saudio_clear(_saudio.backend.buffer, (size_t)num_bytes); - } - } - int res = (int) _saudio.backend.buffer; - return res; - } - else { - return 0; - } -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -/* setup the WebAudio context and attach a ScriptProcessorNode */ -EM_JS(int, saudio_js_init, (int sample_rate, int num_channels, int buffer_size), { - Module._saudio_context = null; - Module._saudio_node = null; - if (typeof AudioContext !== 'undefined') { - Module._saudio_context = new AudioContext({ - sampleRate: sample_rate, - latencyHint: 'interactive', - }); - } - else { - Module._saudio_context = null; - console.log('sokol_audio.h: no WebAudio support'); - } - if (Module._saudio_context) { - console.log('sokol_audio.h: sample rate ', Module._saudio_context.sampleRate); - Module._saudio_node = Module._saudio_context.createScriptProcessor(buffer_size, 0, num_channels); - Module._saudio_node.onaudioprocess = (event) => { - const num_frames = event.outputBuffer.length; - const ptr = __saudio_emsc_pull(num_frames); - if (ptr) { - const num_channels = event.outputBuffer.numberOfChannels; - for (let chn = 0; chn < num_channels; chn++) { - const chan = event.outputBuffer.getChannelData(chn); - for (let i = 0; i < num_frames; i++) { - chan[i] = HEAPF32[(ptr>>2) + ((num_channels*i)+chn)] - } - } - } - }; - Module._saudio_node.connect(Module._saudio_context.destination); - - // in some browsers, WebAudio needs to be activated on a user action - const resume_webaudio = () => { - if (Module._saudio_context) { - if (Module._saudio_context.state === 'suspended') { - Module._saudio_context.resume(); - } - } - }; - document.addEventListener('click', resume_webaudio, {once:true}); - document.addEventListener('touchend', resume_webaudio, {once:true}); - document.addEventListener('keydown', resume_webaudio, {once:true}); - return 1; - } - else { - return 0; - } -}); - -/* shutdown the WebAudioContext and ScriptProcessorNode */ -EM_JS(void, saudio_js_shutdown, (void), { - \x2F\x2A\x2A @suppress {missingProperties} \x2A\x2F - const ctx = Module._saudio_context; - if (ctx !== null) { - if (Module._saudio_node) { - Module._saudio_node.disconnect(); - } - ctx.close(); - Module._saudio_context = null; - Module._saudio_node = null; - } -}); - -/* get the actual sample rate back from the WebAudio context */ -EM_JS(int, saudio_js_sample_rate, (void), { - if (Module._saudio_context) { - return Module._saudio_context.sampleRate; - } - else { - return 0; - } -}); - -/* get the actual buffer size in number of frames */ -EM_JS(int, saudio_js_buffer_frames, (void), { - if (Module._saudio_node) { - return Module._saudio_node.bufferSize; - } - else { - return 0; - } -}); - -/* return 1 if the WebAudio context is currently suspended, else 0 */ -EM_JS(int, saudio_js_suspended, (void), { - if (Module._saudio_context) { - if (Module._saudio_context.state === 'suspended') { - return 1; - } - else { - return 0; - } - } -}); - -_SOKOL_PRIVATE bool _saudio_webaudio_backend_init(void) { - if (saudio_js_init(_saudio.sample_rate, _saudio.num_channels, _saudio.buffer_frames)) { - _saudio.bytes_per_frame = (int)sizeof(float) * _saudio.num_channels; - _saudio.sample_rate = saudio_js_sample_rate(); - _saudio.buffer_frames = saudio_js_buffer_frames(); - const size_t buf_size = (size_t) (_saudio.buffer_frames * _saudio.bytes_per_frame); - _saudio.backend.buffer = (uint8_t*) _saudio_malloc(buf_size); - return true; - } - else { - return false; - } -} - -_SOKOL_PRIVATE void _saudio_webaudio_backend_shutdown(void) { - saudio_js_shutdown(); - if (_saudio.backend.buffer) { - _saudio_free(_saudio.backend.buffer); - _saudio.backend.buffer = 0; - } -} - -// █████ █████ ██ ██ ██████ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██████ ██████ ██ ██████ -// -// >>aaudio -#elif defined(SAUDIO_ANDROID_AAUDIO) - -_SOKOL_PRIVATE aaudio_data_callback_result_t _saudio_aaudio_data_callback(AAudioStream* stream, void* user_data, void* audio_data, int32_t num_frames) { - _SOKOL_UNUSED(user_data); - _SOKOL_UNUSED(stream); - if (_saudio_has_callback()) { - _saudio_stream_callback((float*)audio_data, (int)num_frames, _saudio.num_channels); - } - else { - uint8_t* ptr = (uint8_t*)audio_data; - int num_bytes = _saudio.bytes_per_frame * num_frames; - if (0 == _saudio_fifo_read(&_saudio.fifo, ptr, num_bytes)) { - // not enough read data available, fill the entire buffer with silence - memset(ptr, 0, (size_t)num_bytes); - } - } - return AAUDIO_CALLBACK_RESULT_CONTINUE; -} - -_SOKOL_PRIVATE bool _saudio_aaudio_start_stream(void) { - if (AAudioStreamBuilder_openStream(_saudio.backend.builder, &_saudio.backend.stream) != AAUDIO_OK) { - _SAUDIO_ERROR(AAUDIO_STREAMBUILDER_OPEN_STREAM_FAILED); - return false; - } - AAudioStream_requestStart(_saudio.backend.stream); - return true; -} - -_SOKOL_PRIVATE void _saudio_aaudio_stop_stream(void) { - if (_saudio.backend.stream) { - AAudioStream_requestStop(_saudio.backend.stream); - AAudioStream_close(_saudio.backend.stream); - _saudio.backend.stream = 0; - } -} - -_SOKOL_PRIVATE void* _saudio_aaudio_restart_stream_thread_fn(void* param) { - _SOKOL_UNUSED(param); - _SAUDIO_WARN(AAUDIO_RESTARTING_STREAM_AFTER_ERROR); - pthread_mutex_lock(&_saudio.backend.mutex); - _saudio_aaudio_stop_stream(); - _saudio_aaudio_start_stream(); - pthread_mutex_unlock(&_saudio.backend.mutex); - return 0; -} - -_SOKOL_PRIVATE void _saudio_aaudio_error_callback(AAudioStream* stream, void* user_data, aaudio_result_t error) { - _SOKOL_UNUSED(stream); - _SOKOL_UNUSED(user_data); - if (error == AAUDIO_ERROR_DISCONNECTED) { - if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_aaudio_restart_stream_thread_fn, 0)) { - _SAUDIO_ERROR(AAUDIO_PTHREAD_CREATE_FAILED); - } - } -} - -_SOKOL_PRIVATE void _saudio_aaudio_backend_shutdown(void) { - pthread_mutex_lock(&_saudio.backend.mutex); - _saudio_aaudio_stop_stream(); - pthread_mutex_unlock(&_saudio.backend.mutex); - if (_saudio.backend.builder) { - AAudioStreamBuilder_delete(_saudio.backend.builder); - _saudio.backend.builder = 0; - } - pthread_mutex_destroy(&_saudio.backend.mutex); -} - -_SOKOL_PRIVATE bool _saudio_aaudio_backend_init(void) { - _SAUDIO_INFO(USING_AAUDIO_BACKEND); - - _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float); - - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutex_init(&_saudio.backend.mutex, &attr); - - if (AAudio_createStreamBuilder(&_saudio.backend.builder) != AAUDIO_OK) { - _SAUDIO_ERROR(AAUDIO_CREATE_STREAMBUILDER_FAILED); - _saudio_aaudio_backend_shutdown(); - return false; - } - - AAudioStreamBuilder_setFormat(_saudio.backend.builder, AAUDIO_FORMAT_PCM_FLOAT); - AAudioStreamBuilder_setSampleRate(_saudio.backend.builder, _saudio.sample_rate); - AAudioStreamBuilder_setChannelCount(_saudio.backend.builder, _saudio.num_channels); - AAudioStreamBuilder_setBufferCapacityInFrames(_saudio.backend.builder, _saudio.buffer_frames * 2); - AAudioStreamBuilder_setFramesPerDataCallback(_saudio.backend.builder, _saudio.buffer_frames); - AAudioStreamBuilder_setDataCallback(_saudio.backend.builder, _saudio_aaudio_data_callback, 0); - AAudioStreamBuilder_setErrorCallback(_saudio.backend.builder, _saudio_aaudio_error_callback, 0); - - if (!_saudio_aaudio_start_stream()) { - _saudio_aaudio_backend_shutdown(); - return false; - } - - return true; -} - -// ██████ ██████ ███████ ███ ██ ███████ ██ ███████ ███████ -// ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ -// ██ ██ ██████ █████ ██ ██ ██ ███████ ██ █████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ███████ ██ ████ ███████ ███████ ███████ ███████ -// -// >>opensles -// >>sles -#elif defined(SAUDIO_ANDROID_SLES) - -_SOKOL_PRIVATE void _saudio_sles_semaphore_init(_saudio_sles_semaphore_t* sem) { - sem->count = 0; - int r = pthread_mutex_init(&sem->mutex, NULL); - SOKOL_ASSERT(r == 0); - r = pthread_cond_init(&sem->cond, NULL); - SOKOL_ASSERT(r == 0); - (void)(r); -} - -_SOKOL_PRIVATE void _saudio_sles_semaphore_destroy(_saudio_sles_semaphore_t* sem) { - pthread_cond_destroy(&sem->cond); - pthread_mutex_destroy(&sem->mutex); -} - -_SOKOL_PRIVATE void _saudio_sles_semaphore_post(_saudio_sles_semaphore_t* sem, int count) { - int r = pthread_mutex_lock(&sem->mutex); - SOKOL_ASSERT(r == 0); - for (int ii = 0; ii < count; ii++) { - r = pthread_cond_signal(&sem->cond); - SOKOL_ASSERT(r == 0); - } - sem->count += count; - r = pthread_mutex_unlock(&sem->mutex); - SOKOL_ASSERT(r == 0); - (void)(r); -} - -_SOKOL_PRIVATE bool _saudio_sles_semaphore_wait(_saudio_sles_semaphore_t* sem) { - int r = pthread_mutex_lock(&sem->mutex); - SOKOL_ASSERT(r == 0); - while (r == 0 && sem->count <= 0) { - r = pthread_cond_wait(&sem->cond, &sem->mutex); - } - bool ok = (r == 0); - if (ok) { - --sem->count; - } - r = pthread_mutex_unlock(&sem->mutex); - (void)(r); - return ok; -} - -/* fill intermediate buffer with new data and reset buffer_pos */ -_SOKOL_PRIVATE void _saudio_sles_fill_buffer(void) { - int src_buffer_frames = _saudio.buffer_frames; - if (_saudio_has_callback()) { - _saudio_stream_callback(_saudio.backend.src_buffer, src_buffer_frames, _saudio.num_channels); - } - else { - const int src_buffer_byte_size = src_buffer_frames * _saudio.num_channels * (int)sizeof(float); - if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.src_buffer, src_buffer_byte_size)) { - /* not enough read data available, fill the entire buffer with silence */ - _saudio_clear(_saudio.backend.src_buffer, (size_t)src_buffer_byte_size); - } - } -} - -_SOKOL_PRIVATE void SLAPIENTRY _saudio_sles_play_cb(SLPlayItf player, void *context, SLuint32 event) { - _SOKOL_UNUSED(context); - _SOKOL_UNUSED(player); - if (event & SL_PLAYEVENT_HEADATEND) { - _saudio_sles_semaphore_post(&_saudio.backend.buffer_sem, 1); - } -} - -_SOKOL_PRIVATE void* _saudio_sles_thread_fn(void* param) { - _SOKOL_UNUSED(param); - while (!_saudio.backend.thread_stop) { - /* get next output buffer, advance, next buffer. */ - int16_t* out_buffer = _saudio.backend.output_buffers[_saudio.backend.active_buffer]; - _saudio.backend.active_buffer = (_saudio.backend.active_buffer + 1) % SAUDIO_SLES_NUM_BUFFERS; - int16_t* next_buffer = _saudio.backend.output_buffers[_saudio.backend.active_buffer]; - - /* queue this buffer */ - const int buffer_size_bytes = _saudio.buffer_frames * _saudio.num_channels * (int)sizeof(short); - (*_saudio.backend.player_buffer_queue)->Enqueue(_saudio.backend.player_buffer_queue, out_buffer, (SLuint32)buffer_size_bytes); - - /* fill the next buffer */ - _saudio_sles_fill_buffer(); - const int num_samples = _saudio.num_channels * _saudio.buffer_frames; - for (int i = 0; i < num_samples; ++i) { - next_buffer[i] = (int16_t) (_saudio.backend.src_buffer[i] * 0x7FFF); - } - - _saudio_sles_semaphore_wait(&_saudio.backend.buffer_sem); - } - - return 0; -} - -_SOKOL_PRIVATE void _saudio_sles_backend_shutdown(void) { - _saudio.backend.thread_stop = 1; - pthread_join(_saudio.backend.thread, 0); - - if (_saudio.backend.player_obj) { - (*_saudio.backend.player_obj)->Destroy(_saudio.backend.player_obj); - } - - if (_saudio.backend.output_mix_obj) { - (*_saudio.backend.output_mix_obj)->Destroy(_saudio.backend.output_mix_obj); - } - - if (_saudio.backend.engine_obj) { - (*_saudio.backend.engine_obj)->Destroy(_saudio.backend.engine_obj); - } - - for (int i = 0; i < SAUDIO_SLES_NUM_BUFFERS; i++) { - _saudio_free(_saudio.backend.output_buffers[i]); - } - _saudio_free(_saudio.backend.src_buffer); -} - -_SOKOL_PRIVATE bool _saudio_sles_backend_init(void) { - _SAUDIO_INFO(USING_SLES_BACKEND); - - _saudio.bytes_per_frame = (int)sizeof(float) * _saudio.num_channels; - - for (int i = 0; i < SAUDIO_SLES_NUM_BUFFERS; ++i) { - const int buffer_size_bytes = (int)sizeof(int16_t) * _saudio.num_channels * _saudio.buffer_frames; - _saudio.backend.output_buffers[i] = (int16_t*) _saudio_malloc_clear((size_t)buffer_size_bytes); - } - - { - const int buffer_size_bytes = _saudio.bytes_per_frame * _saudio.buffer_frames; - _saudio.backend.src_buffer = (float*) _saudio_malloc_clear((size_t)buffer_size_bytes); - } - - /* Create engine */ - const SLEngineOption opts[] = { { SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE } }; - if (slCreateEngine(&_saudio.backend.engine_obj, 1, opts, 0, NULL, NULL ) != SL_RESULT_SUCCESS) { - _SAUDIO_ERROR(SLES_CREATE_ENGINE_FAILED); - _saudio_sles_backend_shutdown(); - return false; - } - - (*_saudio.backend.engine_obj)->Realize(_saudio.backend.engine_obj, SL_BOOLEAN_FALSE); - if ((*_saudio.backend.engine_obj)->GetInterface(_saudio.backend.engine_obj, SL_IID_ENGINE, &_saudio.backend.engine) != SL_RESULT_SUCCESS) { - _SAUDIO_ERROR(SLES_ENGINE_GET_ENGINE_INTERFACE_FAILED); - _saudio_sles_backend_shutdown(); - return false; - } - - /* Create output mix. */ - { - const SLInterfaceID ids[] = { SL_IID_VOLUME }; - const SLboolean req[] = { SL_BOOLEAN_FALSE }; - - if ((*_saudio.backend.engine)->CreateOutputMix(_saudio.backend.engine, &_saudio.backend.output_mix_obj, 1, ids, req) != SL_RESULT_SUCCESS) { - _SAUDIO_ERROR(SLES_CREATE_OUTPUT_MIX_FAILED); - _saudio_sles_backend_shutdown(); - return false; - } - (*_saudio.backend.output_mix_obj)->Realize(_saudio.backend.output_mix_obj, SL_BOOLEAN_FALSE); - - if ((*_saudio.backend.output_mix_obj)->GetInterface(_saudio.backend.output_mix_obj, SL_IID_VOLUME, &_saudio.backend.output_mix_vol) != SL_RESULT_SUCCESS) { - _SAUDIO_WARN(SLES_MIXER_GET_VOLUME_INTERFACE_FAILED); - } - } - - /* android buffer queue */ - _saudio.backend.in_locator.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - _saudio.backend.in_locator.numBuffers = SAUDIO_SLES_NUM_BUFFERS; - - /* data format */ - SLDataFormat_PCM format; - format.formatType = SL_DATAFORMAT_PCM; - format.numChannels = (SLuint32)_saudio.num_channels; - format.samplesPerSec = (SLuint32) (_saudio.sample_rate * 1000); - format.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; - format.containerSize = 16; - format.endianness = SL_BYTEORDER_LITTLEENDIAN; - - if (_saudio.num_channels == 2) { - format.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - } else { - format.channelMask = SL_SPEAKER_FRONT_CENTER; - } - - SLDataSource src; - src.pLocator = &_saudio.backend.in_locator; - src.pFormat = &format; - - /* Output mix. */ - _saudio.backend.out_locator.locatorType = SL_DATALOCATOR_OUTPUTMIX; - _saudio.backend.out_locator.outputMix = _saudio.backend.output_mix_obj; - - _saudio.backend.dst_data_sink.pLocator = &_saudio.backend.out_locator; - _saudio.backend.dst_data_sink.pFormat = NULL; - - /* setup player */ - { - const SLInterfaceID ids[] = { SL_IID_VOLUME, SL_IID_ANDROIDSIMPLEBUFFERQUEUE }; - const SLboolean req[] = { SL_BOOLEAN_FALSE, SL_BOOLEAN_TRUE }; - - if ((*_saudio.backend.engine)->CreateAudioPlayer(_saudio.backend.engine, &_saudio.backend.player_obj, &src, &_saudio.backend.dst_data_sink, sizeof(ids) / sizeof(ids[0]), ids, req) != SL_RESULT_SUCCESS) - { - _SAUDIO_ERROR(SLES_ENGINE_CREATE_AUDIO_PLAYER_FAILED); - _saudio_sles_backend_shutdown(); - return false; - } - (*_saudio.backend.player_obj)->Realize(_saudio.backend.player_obj, SL_BOOLEAN_FALSE); - - if ((*_saudio.backend.player_obj)->GetInterface(_saudio.backend.player_obj, SL_IID_PLAY, &_saudio.backend.player) != SL_RESULT_SUCCESS) { - _SAUDIO_ERROR(SLES_PLAYER_GET_PLAY_INTERFACE_FAILED); - _saudio_sles_backend_shutdown(); - return false; - } - if ((*_saudio.backend.player_obj)->GetInterface(_saudio.backend.player_obj, SL_IID_VOLUME, &_saudio.backend.player_vol) != SL_RESULT_SUCCESS) { - _SAUDIO_ERROR(SLES_PLAYER_GET_VOLUME_INTERFACE_FAILED); - } - if ((*_saudio.backend.player_obj)->GetInterface(_saudio.backend.player_obj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &_saudio.backend.player_buffer_queue) != SL_RESULT_SUCCESS) { - _SAUDIO_ERROR(SLES_PLAYER_GET_BUFFERQUEUE_INTERFACE_FAILED); - _saudio_sles_backend_shutdown(); - return false; - } - } - - /* begin */ - { - const int buffer_size_bytes = (int)sizeof(int16_t) * _saudio.num_channels * _saudio.buffer_frames; - (*_saudio.backend.player_buffer_queue)->Enqueue(_saudio.backend.player_buffer_queue, _saudio.backend.output_buffers[0], (SLuint32)buffer_size_bytes); - _saudio.backend.active_buffer = (_saudio.backend.active_buffer + 1) % SAUDIO_SLES_NUM_BUFFERS; - - (*_saudio.backend.player)->RegisterCallback(_saudio.backend.player, _saudio_sles_play_cb, NULL); - (*_saudio.backend.player)->SetCallbackEventsMask(_saudio.backend.player, SL_PLAYEVENT_HEADATEND); - (*_saudio.backend.player)->SetPlayState(_saudio.backend.player, SL_PLAYSTATE_PLAYING); - } - - /* create the buffer-streaming start thread */ - if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_sles_thread_fn, 0)) { - _saudio_sles_backend_shutdown(); - return false; - } - - return true; -} - -// ██████ ██████ ██████ ███████ █████ ██ ██ ██████ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██████ █████ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██ ██ ███████ ██ ██ ██████ ██████ ██ ██████ -// -// >>coreaudio -#elif defined(_SAUDIO_APPLE) - -#if defined(_SAUDIO_IOS) -#if __has_feature(objc_arc) -#define _SAUDIO_OBJC_RELEASE(obj) { obj = nil; } -#else -#define _SAUDIO_OBJC_RELEASE(obj) { [obj release]; obj = nil; } -#endif - -@interface _saudio_interruption_handler : NSObject { } -@end - -@implementation _saudio_interruption_handler --(id)init { - self = [super init]; - AVAudioSession* session = [AVAudioSession sharedInstance]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_interruption:) name:AVAudioSessionInterruptionNotification object:session]; - return self; -} - --(void)dealloc { - [self remove_handler]; - #if !__has_feature(objc_arc) - [super dealloc]; - #endif -} - --(void)remove_handler { - [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVAudioSessionInterruptionNotification" object:nil]; -} - --(void)handle_interruption:(NSNotification*)notification { - AVAudioSession* session = [AVAudioSession sharedInstance]; - SOKOL_ASSERT(session); - NSDictionary* dict = notification.userInfo; - SOKOL_ASSERT(dict); - NSInteger type = [[dict valueForKey:AVAudioSessionInterruptionTypeKey] integerValue]; - switch (type) { - case AVAudioSessionInterruptionTypeBegan: - if (_saudio.backend.ca_audio_queue) { - AudioQueuePause(_saudio.backend.ca_audio_queue); - } - [session setActive:false error:nil]; - break; - case AVAudioSessionInterruptionTypeEnded: - [session setActive:true error:nil]; - if (_saudio.backend.ca_audio_queue) { - AudioQueueStart(_saudio.backend.ca_audio_queue, NULL); - } - break; - default: - break; - } -} -@end -#endif // _SAUDIO_IOS - -/* NOTE: the buffer data callback is called on a separate thread! */ -_SOKOL_PRIVATE void _saudio_coreaudio_callback(void* user_data, _saudio_AudioQueueRef queue, _saudio_AudioQueueBufferRef buffer) { - _SOKOL_UNUSED(user_data); - if (_saudio_has_callback()) { - const int num_frames = (int)buffer->mAudioDataByteSize / _saudio.bytes_per_frame; - const int num_channels = _saudio.num_channels; - _saudio_stream_callback((float*)buffer->mAudioData, num_frames, num_channels); - } - else { - uint8_t* ptr = (uint8_t*)buffer->mAudioData; - int num_bytes = (int) buffer->mAudioDataByteSize; - if (0 == _saudio_fifo_read(&_saudio.fifo, ptr, num_bytes)) { - /* not enough read data available, fill the entire buffer with silence */ - _saudio_clear(ptr, (size_t)num_bytes); - } - } - AudioQueueEnqueueBuffer(queue, buffer, 0, NULL); -} - -_SOKOL_PRIVATE void _saudio_coreaudio_backend_shutdown(void) { - if (_saudio.backend.ca_audio_queue) { - AudioQueueStop(_saudio.backend.ca_audio_queue, true); - AudioQueueDispose(_saudio.backend.ca_audio_queue, false); - _saudio.backend.ca_audio_queue = 0; - } - #if defined(_SAUDIO_IOS) - /* remove interruption handler */ - if (_saudio.backend.ca_interruption_handler != nil) { - [_saudio.backend.ca_interruption_handler remove_handler]; - _SAUDIO_OBJC_RELEASE(_saudio.backend.ca_interruption_handler); - } - /* deactivate audio session */ - AVAudioSession* session = [AVAudioSession sharedInstance]; - SOKOL_ASSERT(session); - [session setActive:false error:nil];; - #endif // _SAUDIO_IOS -} - -_SOKOL_PRIVATE bool _saudio_coreaudio_backend_init(void) { - SOKOL_ASSERT(0 == _saudio.backend.ca_audio_queue); - - #if defined(_SAUDIO_IOS) - /* activate audio session */ - AVAudioSession* session = [AVAudioSession sharedInstance]; - SOKOL_ASSERT(session != nil); - [session setCategory: AVAudioSessionCategoryPlayback error:nil]; - [session setActive:true error:nil]; - - /* create interruption handler */ - _saudio.backend.ca_interruption_handler = [[_saudio_interruption_handler alloc] init]; - #endif - - /* create an audio queue with fp32 samples */ - _saudio_AudioStreamBasicDescription fmt; - _saudio_clear(&fmt, sizeof(fmt)); - fmt.mSampleRate = (double) _saudio.sample_rate; - fmt.mFormatID = _saudio_kAudioFormatLinearPCM; - fmt.mFormatFlags = _saudio_kLinearPCMFormatFlagIsFloat | _saudio_kAudioFormatFlagIsPacked; - fmt.mFramesPerPacket = 1; - fmt.mChannelsPerFrame = (uint32_t) _saudio.num_channels; - fmt.mBytesPerFrame = (uint32_t)sizeof(float) * (uint32_t)_saudio.num_channels; - fmt.mBytesPerPacket = fmt.mBytesPerFrame; - fmt.mBitsPerChannel = 32; - _saudio_OSStatus res = AudioQueueNewOutput(&fmt, _saudio_coreaudio_callback, 0, NULL, NULL, 0, &_saudio.backend.ca_audio_queue); - if (0 != res) { - _SAUDIO_ERROR(COREAUDIO_NEW_OUTPUT_FAILED); - return false; - } - SOKOL_ASSERT(_saudio.backend.ca_audio_queue); - - /* create 2 audio buffers */ - for (int i = 0; i < 2; i++) { - _saudio_AudioQueueBufferRef buf = NULL; - const uint32_t buf_byte_size = (uint32_t)_saudio.buffer_frames * fmt.mBytesPerFrame; - res = AudioQueueAllocateBuffer(_saudio.backend.ca_audio_queue, buf_byte_size, &buf); - if (0 != res) { - _SAUDIO_ERROR(COREAUDIO_ALLOCATE_BUFFER_FAILED); - _saudio_coreaudio_backend_shutdown(); - return false; - } - buf->mAudioDataByteSize = buf_byte_size; - _saudio_clear(buf->mAudioData, buf->mAudioDataByteSize); - AudioQueueEnqueueBuffer(_saudio.backend.ca_audio_queue, buf, 0, NULL); - } - - /* init or modify actual playback parameters */ - _saudio.bytes_per_frame = (int)fmt.mBytesPerFrame; - - /* ...and start playback */ - res = AudioQueueStart(_saudio.backend.ca_audio_queue, NULL); - if (0 != res) { - _SAUDIO_ERROR(COREAUDIO_START_FAILED); - _saudio_coreaudio_backend_shutdown(); - return false; - } - return true; -} - -#else -#error "unsupported platform" -#endif - -bool _saudio_backend_init(void) { - #if defined(SOKOL_DUMMY_BACKEND) - return _saudio_dummy_backend_init(); - #elif defined(_SAUDIO_LINUX) - return _saudio_alsa_backend_init(); - #elif defined(_SAUDIO_WINDOWS) - return _saudio_wasapi_backend_init(); - #elif defined(_SAUDIO_EMSCRIPTEN) - return _saudio_webaudio_backend_init(); - #elif defined(SAUDIO_ANDROID_AAUDIO) - return _saudio_aaudio_backend_init(); - #elif defined(SAUDIO_ANDROID_SLES) - return _saudio_sles_backend_init(); - #elif defined(_SAUDIO_APPLE) - return _saudio_coreaudio_backend_init(); - #else - #error "unknown platform" - #endif -} - -void _saudio_backend_shutdown(void) { - #if defined(SOKOL_DUMMY_BACKEND) - _saudio_dummy_backend_shutdown(); - #elif defined(_SAUDIO_LINUX) - _saudio_alsa_backend_shutdown(); - #elif defined(_SAUDIO_WINDOWS) - _saudio_wasapi_backend_shutdown(); - #elif defined(_SAUDIO_EMSCRIPTEN) - _saudio_webaudio_backend_shutdown(); - #elif defined(SAUDIO_ANDROID_AAUDIO) - _saudio_aaudio_backend_shutdown(); - #elif defined(SAUDIO_ANDROID_SLES) - _saudio_sles_backend_shutdown(); - #elif defined(_SAUDIO_APPLE) - return _saudio_coreaudio_backend_shutdown(); - #else - #error "unknown platform" - #endif -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) { - SOKOL_ASSERT(!_saudio.valid); - SOKOL_ASSERT(!_saudio.setup_called); - SOKOL_ASSERT(desc); - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - _saudio_clear(&_saudio, sizeof(_saudio)); - _saudio.setup_called = true; - _saudio.desc = *desc; - _saudio.stream_cb = desc->stream_cb; - _saudio.stream_userdata_cb = desc->stream_userdata_cb; - _saudio.user_data = desc->user_data; - _saudio.sample_rate = _saudio_def(_saudio.desc.sample_rate, _SAUDIO_DEFAULT_SAMPLE_RATE); - _saudio.buffer_frames = _saudio_def(_saudio.desc.buffer_frames, _SAUDIO_DEFAULT_BUFFER_FRAMES); - _saudio.packet_frames = _saudio_def(_saudio.desc.packet_frames, _SAUDIO_DEFAULT_PACKET_FRAMES); - _saudio.num_packets = _saudio_def(_saudio.desc.num_packets, _SAUDIO_DEFAULT_NUM_PACKETS); - _saudio.num_channels = _saudio_def(_saudio.desc.num_channels, 1); - _saudio_fifo_init_mutex(&_saudio.fifo); - if (_saudio_backend_init()) { - /* the backend might not support the requested exact buffer size, - make sure the actual buffer size is still a multiple of - the requested packet size - */ - if (0 != (_saudio.buffer_frames % _saudio.packet_frames)) { - _SAUDIO_ERROR(BACKEND_BUFFER_SIZE_ISNT_MULTIPLE_OF_PACKET_SIZE); - _saudio_backend_shutdown(); - return; - } - SOKOL_ASSERT(_saudio.bytes_per_frame > 0); - _saudio_fifo_init(&_saudio.fifo, _saudio.packet_frames * _saudio.bytes_per_frame, _saudio.num_packets); - _saudio.valid = true; - } - else { - _saudio_fifo_destroy_mutex(&_saudio.fifo); - } -} - -SOKOL_API_IMPL void saudio_shutdown(void) { - SOKOL_ASSERT(_saudio.setup_called); - _saudio.setup_called = false; - if (_saudio.valid) { - _saudio_backend_shutdown(); - _saudio_fifo_shutdown(&_saudio.fifo); - _saudio_fifo_destroy_mutex(&_saudio.fifo); - _saudio.valid = false; - } -} - -SOKOL_API_IMPL bool saudio_isvalid(void) { - return _saudio.valid; -} - -SOKOL_API_IMPL void* saudio_userdata(void) { - SOKOL_ASSERT(_saudio.setup_called); - return _saudio.desc.user_data; -} - -SOKOL_API_IMPL saudio_desc saudio_query_desc(void) { - SOKOL_ASSERT(_saudio.setup_called); - return _saudio.desc; -} - -SOKOL_API_IMPL int saudio_sample_rate(void) { - SOKOL_ASSERT(_saudio.setup_called); - return _saudio.sample_rate; -} - -SOKOL_API_IMPL int saudio_buffer_frames(void) { - SOKOL_ASSERT(_saudio.setup_called); - return _saudio.buffer_frames; -} - -SOKOL_API_IMPL int saudio_channels(void) { - SOKOL_ASSERT(_saudio.setup_called); - return _saudio.num_channels; -} - -SOKOL_API_IMPL bool saudio_suspended(void) { - SOKOL_ASSERT(_saudio.setup_called); - #if defined(_SAUDIO_EMSCRIPTEN) - if (_saudio.valid) { - return 1 == saudio_js_suspended(); - } - else { - return false; - } - #else - return false; - #endif -} - -SOKOL_API_IMPL int saudio_expect(void) { - SOKOL_ASSERT(_saudio.setup_called); - if (_saudio.valid) { - const int num_frames = _saudio_fifo_writable_bytes(&_saudio.fifo) / _saudio.bytes_per_frame; - return num_frames; - } - else { - return 0; - } -} - -SOKOL_API_IMPL int saudio_push(const float* frames, int num_frames) { - SOKOL_ASSERT(_saudio.setup_called); - SOKOL_ASSERT(frames && (num_frames > 0)); - if (_saudio.valid) { - const int num_bytes = num_frames * _saudio.bytes_per_frame; - const int num_written = _saudio_fifo_write(&_saudio.fifo, (const uint8_t*)frames, num_bytes); - return num_written / _saudio.bytes_per_frame; - } - else { - return 0; - } -} - -#undef _saudio_def -#undef _saudio_def_flt - -#if defined(_SAUDIO_WINDOWS) -#ifdef _MSC_VER -#pragma warning(pop) -#endif -#endif - -#endif /* SOKOL_AUDIO_IMPL */ diff --git a/source/thirdparty/sokol/sokol_fetch.h b/source/thirdparty/sokol/sokol_fetch.h deleted file mode 100644 index 2cc49312..00000000 --- a/source/thirdparty/sokol/sokol_fetch.h +++ /dev/null @@ -1,2819 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_FETCH_IMPL) -#define SOKOL_FETCH_IMPL -#endif -#ifndef SOKOL_FETCH_INCLUDED -/* - sokol_fetch.h -- asynchronous data loading/streaming - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_FETCH_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - Optionally provide the following defines with your own implementations: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - SOKOL_FETCH_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_FETCH_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - SFETCH_MAX_PATH - max length of UTF-8 filesystem path / URL (default: 1024 bytes) - SFETCH_MAX_USERDATA_UINT64 - max size of embedded userdata in number of uint64_t, userdata - will be copied into an 8-byte aligned memory region associated - with each in-flight request, default value is 16 (== 128 bytes) - SFETCH_MAX_CHANNELS - max number of IO channels (default is 16, also see sfetch_desc_t.num_channels) - - If sokol_fetch.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_FETCH_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - NOTE: The following documentation talks a lot about "IO threads". Actual - threads are only used on platforms where threads are available. The web - version (emscripten/wasm) doesn't use POSIX-style threads, but instead - asynchronous Javascript calls chained together by callbacks. The actual - source code differences between the two approaches have been kept to - a minimum though. - - FEATURE OVERVIEW - ================ - - - Asynchronously load complete files, or stream files incrementally via - HTTP (on web platform), or the local file system (on native platforms) - - - Request / response-callback model, user code sends a request - to initiate a file-load, sokol_fetch.h calls the response callback - on the same thread when data is ready or user-code needs - to respond otherwise - - - Not limited to the main-thread or a single thread: A sokol-fetch - "context" can live on any thread, and multiple contexts - can operate side-by-side on different threads. - - - Memory management for data buffers is under full control of user code. - sokol_fetch.h won't allocate memory after it has been setup. - - - Automatic rate-limiting guarantees that only a maximum number of - requests is processed at any one time, allowing a zero-allocation - model, where all data is streamed into fixed-size, pre-allocated - buffers. - - - Active Requests can be paused, continued and cancelled from anywhere - in the user-thread which sent this request. - - - TL;DR EXAMPLE CODE - ================== - This is the most-simple example code to load a single data file with a - known maximum size: - - (1) initialize sokol-fetch with default parameters (but NOTE that the - default setup parameters provide a safe-but-slow "serialized" - operation). In order to see any logging output in case or errors - you should always provide a logging function - (such as 'slog_func' from sokol_log.h): - - sfetch_setup(&(sfetch_desc_t){ .logger.func = slog_func }); - - (2) send a fetch-request to load a file from the current directory - into a buffer big enough to hold the entire file content: - - static uint8_t buf[MAX_FILE_SIZE]; - - sfetch_send(&(sfetch_request_t){ - .path = "my_file.txt", - .callback = response_callback, - .buffer = { - .ptr = buf, - .size = sizeof(buf) - } - }); - - If 'buf' is a value (e.g. an array or struct item), the .buffer item can - be initialized with the SFETCH_RANGE() helper macro: - - sfetch_send(&(sfetch_request_t){ - .path = "my_file.txt", - .callback = response_callback, - .buffer = SFETCH_RANGE(buf) - }); - - (3) write a 'response-callback' function, this will be called whenever - the user-code must respond to state changes of the request - (most importantly when data has been loaded): - - void response_callback(const sfetch_response_t* response) { - if (response->fetched) { - // data has been loaded, and is available via the - // sfetch_range_t struct item 'data': - const void* ptr = response->data.ptr; - size_t num_bytes = response->data.size; - } - if (response->finished) { - // the 'finished'-flag is the catch-all flag for when the request - // is finished, no matter if loading was successful or failed, - // so any cleanup-work should happen here... - ... - if (response->failed) { - // 'failed' is true in (addition to 'finished') if something - // went wrong (file doesn't exist, or less bytes could be - // read from the file than expected) - } - } - } - - (4) pump the sokol-fetch message queues, and invoke response callbacks - by calling: - - sfetch_dowork(); - - In an event-driven app this should be called in the event loop. If you - use sokol-app this would be in your frame_cb function. - - (5) finally, call sfetch_shutdown() at the end of the application: - - There's many other loading-scenarios, for instance one doesn't have to - provide a buffer upfront, this can also happen in the response callback. - - Or it's possible to stream huge files into small fixed-size buffer, - complete with pausing and continuing the download. - - It's also possible to improve the 'pipeline throughput' by fetching - multiple files in parallel, but at the same time limit the maximum - number of requests that can be 'in-flight'. - - For how this all works, please read the following documentation sections :) - - - API DOCUMENTATION - ================= - - void sfetch_setup(const sfetch_desc_t* desc) - -------------------------------------------- - First call sfetch_setup(const sfetch_desc_t*) on any thread before calling - any other sokol-fetch functions on the same thread. - - sfetch_setup() takes a pointer to an sfetch_desc_t struct with setup - parameters. Parameters which should use their default values must - be zero-initialized: - - - max_requests (uint32_t): - The maximum number of requests that can be alive at any time, the - default is 128. - - - num_channels (uint32_t): - The number of "IO channels" used to parallelize and prioritize - requests, the default is 1. - - - num_lanes (uint32_t): - The number of "lanes" on a single channel. Each request which is - currently 'inflight' on a channel occupies one lane until the - request is finished. This is used for automatic rate-limiting - (search below for CHANNELS AND LANES for more details). The - default number of lanes is 1. - - For example, to setup sokol-fetch for max 1024 active requests, 4 channels, - and 8 lanes per channel in C99: - - sfetch_setup(&(sfetch_desc_t){ - .max_requests = 1024, - .num_channels = 4, - .num_lanes = 8 - }); - - sfetch_setup() is the only place where sokol-fetch will allocate memory. - - NOTE that the default setup parameters of 1 channel and 1 lane per channel - has a very poor 'pipeline throughput' since this essentially serializes - IO requests (a new request will only be processed when the last one has - finished), and since each request needs at least one roundtrip between - the user- and IO-thread the throughput will be at most one request per - frame. Search for LATENCY AND THROUGHPUT below for more information on - how to increase throughput. - - NOTE that you can call sfetch_setup() on multiple threads, each thread - will get its own thread-local sokol-fetch instance, which will work - independently from sokol-fetch instances on other threads. - - void sfetch_shutdown(void) - -------------------------- - Call sfetch_shutdown() at the end of the application to stop any - IO threads and free all memory that was allocated in sfetch_setup(). - - sfetch_handle_t sfetch_send(const sfetch_request_t* request) - ------------------------------------------------------------ - Call sfetch_send() to start loading data, the function takes a pointer to an - sfetch_request_t struct with request parameters and returns a - sfetch_handle_t identifying the request for later calls. At least - a path/URL and callback must be provided: - - sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ - .path = "my_file.txt", - .callback = my_response_callback - }); - - sfetch_send() will return an invalid handle if no request can be allocated - from the internal pool because all available request items are 'in-flight'. - - The sfetch_request_t struct contains the following parameters (optional - parameters that are not provided must be zero-initialized): - - - path (const char*, required) - Pointer to an UTF-8 encoded C string describing the filesystem - path or HTTP URL. The string will be copied into an internal data - structure, and passed "as is" (apart from any required - encoding-conversions) to fopen(), CreateFileW() or - XMLHttpRequest. The maximum length of the string is defined by - the SFETCH_MAX_PATH configuration define, the default is 1024 bytes - including the 0-terminator byte. - - - callback (sfetch_callback_t, required) - Pointer to a response-callback function which is called when the - request needs "user code attention". Search below for REQUEST - STATES AND THE RESPONSE CALLBACK for detailed information about - handling responses in the response callback. - - - channel (uint32_t, optional) - Index of the IO channel where the request should be processed. - Channels are used to parallelize and prioritize requests relative - to each other. Search below for CHANNELS AND LANES for more - information. The default channel is 0. - - - chunk_size (uint32_t, optional) - The chunk_size member is used for streaming data incrementally - in small chunks. After 'chunk_size' bytes have been loaded into - to the streaming buffer, the response callback will be called - with the buffer containing the fetched data for the current chunk. - If chunk_size is 0 (the default), than the whole file will be loaded. - Please search below for CHUNK SIZE AND HTTP COMPRESSION for - important information how streaming works if the web server - is serving compressed data. - - - buffer (sfetch_range_t) - This is a optional pointer/size pair describing a chunk of memory where - data will be loaded into (if no buffer is provided upfront, this - must happen in the response callback). If a buffer is provided, - it must be big enough to either hold the entire file (if chunk_size - is zero), or the *uncompressed* data for one downloaded chunk - (if chunk_size is > 0). - - - user_data (sfetch_range_t) - The user_data ptr/size range struct describe an optional POD blob - (plain-old-data) associated with the request which will be copied(!) - into an internal memory block. The maximum default size of this - memory block is 128 bytes (but can be overridden by defining - SFETCH_MAX_USERDATA_UINT64 before including the notification, note - that this define is in "number of uint64_t", not number of bytes). - The user-data block is 8-byte aligned, and will be copied via - memcpy() (so don't put any C++ "smart members" in there). - - NOTE that request handles are strictly thread-local and only unique - within the thread the handle was created on, and all function calls - involving a request handle must happen on that same thread. - - bool sfetch_handle_valid(sfetch_handle_t request) - ------------------------------------------------- - This checks if the provided request handle is valid, and is associated with - a currently active request. It will return false if: - - - sfetch_send() returned an invalid handle because it couldn't allocate - a new request from the internal request pool (because they're all - in flight) - - the request associated with the handle is no longer alive (because - it either finished successfully, or the request failed for some - reason) - - void sfetch_dowork(void) - ------------------------ - Call sfetch_dowork(void) in regular intervals (for instance once per frame) - on the same thread as sfetch_setup() to "turn the gears". If you are sending - requests but never hear back from them in the response callback function, then - the most likely reason is that you forgot to add the call to sfetch_dowork() - in the per-frame function. - - sfetch_dowork() roughly performs the following work: - - - any new requests that have been sent with sfetch_send() since the - last call to sfetch_dowork() will be dispatched to their IO channels - and assigned a free lane. If all lanes on that channel are occupied - by requests 'in flight', incoming requests must wait until - a lane becomes available - - - for all new requests which have been enqueued on a channel which - don't already have a buffer assigned the response callback will be - called with (response->dispatched == true) so that the response - callback can inspect the dynamically assigned lane and bind a buffer - to the request (search below for CHANNELS AND LANE for more info) - - - a state transition from "user side" to "IO thread side" happens for - each new request that has been dispatched to a channel. - - - requests dispatched to a channel are either forwarded into that - channel's worker thread (on native platforms), or cause an HTTP - request to be sent via an asynchronous XMLHttpRequest (on the web - platform) - - - for all requests which have finished their current IO operation a - state transition from "IO thread side" to "user side" happens, - and the response callback is called so that the fetched data - can be processed. - - - requests which are completely finished (either because the entire - file content has been loaded, or they are in the FAILED state) are - freed (this just changes their state in the 'request pool', no actual - memory is freed) - - - requests which are not yet finished are fed back into the - 'incoming' queue of their channel, and the cycle starts again, this - only happens for requests which perform data streaming (not load - the entire file at once). - - void sfetch_cancel(sfetch_handle_t request) - ------------------------------------------- - This cancels a request in the next sfetch_dowork() call and invokes the - response callback with (response.failed == true) and (response.finished - == true) to give user-code a chance to do any cleanup work for the - request. If sfetch_cancel() is called for a request that is no longer - alive, nothing bad will happen (the call will simply do nothing). - - void sfetch_pause(sfetch_handle_t request) - ------------------------------------------ - This pauses an active request in the next sfetch_dowork() call and puts - it into the PAUSED state. For all requests in PAUSED state, the response - callback will be called in each call to sfetch_dowork() to give user-code - a chance to CONTINUE the request (by calling sfetch_continue()). Pausing - a request makes sense for dynamic rate-limiting in streaming scenarios - (like video/audio streaming with a fixed number of streaming buffers. As - soon as all available buffers are filled with download data, downloading - more data must be prevented to allow video/audio playback to catch up and - free up empty buffers for new download data. - - void sfetch_continue(sfetch_handle_t request) - --------------------------------------------- - Continues a paused request, counterpart to the sfetch_pause() function. - - void sfetch_bind_buffer(sfetch_handle_t request, sfetch_range_t buffer) - ---------------------------------------------------------------------------------------- - This "binds" a new buffer (as pointer/size pair) to an active request. The - function *must* be called from inside the response-callback, and there - must not already be another buffer bound. - - void* sfetch_unbind_buffer(sfetch_handle_t request) - --------------------------------------------------- - This removes the current buffer binding from the request and returns - a pointer to the previous buffer (useful if the buffer was dynamically - allocated and it must be freed). - - sfetch_unbind_buffer() *must* be called from inside the response callback. - - The usual code sequence to bind a different buffer in the response - callback might look like this: - - void response_callback(const sfetch_response_t* response) { - if (response.fetched) { - ... - // switch to a different buffer (in the FETCHED state it is - // guaranteed that the request has a buffer, otherwise it - // would have gone into the FAILED state - void* old_buf_ptr = sfetch_unbind_buffer(response.handle); - free(old_buf_ptr); - void* new_buf_ptr = malloc(new_buf_size); - sfetch_bind_buffer(response.handle, new_buf_ptr, new_buf_size); - } - if (response.finished) { - // unbind and free the currently associated buffer, - // the buffer pointer could be null if the request has failed - // NOTE that it is legal to call free() with a nullptr, - // this happens if the request failed to open its file - // and never goes into the OPENED state - void* buf_ptr = sfetch_unbind_buffer(response.handle); - free(buf_ptr); - } - } - - sfetch_desc_t sfetch_desc(void) - ------------------------------- - sfetch_desc() returns a copy of the sfetch_desc_t struct passed to - sfetch_setup(), with zero-initialized values replaced with - their default values. - - int sfetch_max_userdata_bytes(void) - ----------------------------------- - This returns the value of the SFETCH_MAX_USERDATA_UINT64 config - define, but in number of bytes (so SFETCH_MAX_USERDATA_UINT64*8). - - int sfetch_max_path(void) - ------------------------- - Returns the value of the SFETCH_MAX_PATH config define. - - - REQUEST STATES AND THE RESPONSE CALLBACK - ======================================== - A request goes through a number of states during its lifetime. Depending - on the current state of a request, it will be 'owned' either by the - "user-thread" (where the request was sent) or an IO thread. - - You can think of a request as "ping-ponging" between the IO thread and - user thread, any actual IO work is done on the IO thread, while - invocations of the response-callback happen on the user-thread. - - All state transitions and callback invocations happen inside the - sfetch_dowork() function. - - An active request goes through the following states: - - ALLOCATED (user-thread) - - The request has been allocated in sfetch_send() and is - waiting to be dispatched into its IO channel. When this - happens, the request will transition into the DISPATCHED state. - - DISPATCHED (IO thread) - - The request has been dispatched into its IO channel, and a - lane has been assigned to the request. - - If a buffer was provided in sfetch_send() the request will - immediately transition into the FETCHING state and start loading - data into the buffer. - - If no buffer was provided in sfetch_send(), the response - callback will be called with (response->dispatched == true), - so that the response callback can bind a buffer to the - request. Binding the buffer in the response callback makes - sense if the buffer isn't dynamically allocated, but instead - a pre-allocated buffer must be selected from the request's - channel and lane. - - Note that it isn't possible to get a file size in the response callback - which would help with allocating a buffer of the right size, this is - because it isn't possible in HTTP to query the file size before the - entire file is downloaded (...when the web server serves files compressed). - - If opening the file failed, the request will transition into - the FAILED state with the error code SFETCH_ERROR_FILE_NOT_FOUND. - - FETCHING (IO thread) - - While a request is in the FETCHING state, data will be loaded into - the user-provided buffer. - - If no buffer was provided, the request will go into the FAILED - state with the error code SFETCH_ERROR_NO_BUFFER. - - If a buffer was provided, but it is too small to contain the - fetched data, the request will go into the FAILED state with - error code SFETCH_ERROR_BUFFER_TOO_SMALL. - - If less data can be read from the file than expected, the request - will go into the FAILED state with error code SFETCH_ERROR_UNEXPECTED_EOF. - - If loading data into the provided buffer works as expected, the - request will go into the FETCHED state. - - FETCHED (user thread) - - The request goes into the FETCHED state either when the entire file - has been loaded into the provided buffer (when request.chunk_size == 0), - or a chunk has been loaded (and optionally decompressed) into the - buffer (when request.chunk_size > 0). - - The response callback will be called so that the user-code can - process the loaded data using the following sfetch_response_t struct members: - - - data.ptr: pointer to the start of fetched data - - data.size: the number of bytes in the provided buffer - - data_offset: the byte offset of the loaded data chunk in the - overall file (this is only set to a non-zero value in a streaming - scenario) - - Once all file data has been loaded, the 'finished' flag will be set - in the response callback's sfetch_response_t argument. - - After the user callback returns, and all file data has been loaded - (response.finished flag is set) the request has reached its end-of-life - and will recycled. - - Otherwise, if there's still data to load (because streaming was - requested by providing a non-zero request.chunk_size), the request - will switch back to the FETCHING state to load the next chunk of data. - - Note that it is ok to associate a different buffer or buffer-size - with the request by calling sfetch_bind_buffer() in the response-callback. - - To check in the response callback for the FETCHED state, and - independently whether the request is finished: - - void response_callback(const sfetch_response_t* response) { - if (response->fetched) { - // request is in FETCHED state, the loaded data is available - // in .data.ptr, and the number of bytes that have been - // loaded in .data.size: - const void* data = response->data.ptr; - size_t num_bytes = response->data.size; - } - if (response->finished) { - // the finished flag is set either when all data - // has been loaded, the request has been cancelled, - // or the file operation has failed, this is where - // any required per-request cleanup work should happen - } - } - - - FAILED (user thread) - - A request will transition into the FAILED state in the following situations: - - - if the file doesn't exist or couldn't be opened for other - reasons (SFETCH_ERROR_FILE_NOT_FOUND) - - if no buffer is associated with the request in the FETCHING state - (SFETCH_ERROR_NO_BUFFER) - - if the provided buffer is too small to hold the entire file - (if request.chunk_size == 0), or the (potentially decompressed) - partial data chunk (SFETCH_ERROR_BUFFER_TOO_SMALL) - - if less bytes could be read from the file then expected - (SFETCH_ERROR_UNEXPECTED_EOF) - - if a request has been cancelled via sfetch_cancel() - (SFETCH_ERROR_CANCELLED) - - The response callback will be called once after a request goes into - the FAILED state, with the 'response->finished' and - 'response->failed' flags set to true. - - This gives the user-code a chance to cleanup any resources associated - with the request. - - To check for the failed state in the response callback: - - void response_callback(const sfetch_response_t* response) { - if (response->failed) { - // specifically check for the failed state... - } - // or you can do a catch-all check via the finished-flag: - if (response->finished) { - if (response->failed) { - // if more detailed error handling is needed: - switch (response->error_code) { - ... - } - } - } - } - - PAUSED (user thread) - - A request will transition into the PAUSED state after user-code - calls the function sfetch_pause() on the request's handle. Usually - this happens from within the response-callback in streaming scenarios - when the data streaming needs to wait for a data decoder (like - a video/audio player) to catch up. - - While a request is in PAUSED state, the response-callback will be - called in each sfetch_dowork(), so that the user-code can either - continue the request by calling sfetch_continue(), or cancel - the request by calling sfetch_cancel(). - - When calling sfetch_continue() on a paused request, the request will - transition into the FETCHING state. Otherwise if sfetch_cancel() is - called, the request will switch into the FAILED state. - - To check for the PAUSED state in the response callback: - - void response_callback(const sfetch_response_t* response) { - if (response->paused) { - // we can check here whether the request should - // continue to load data: - if (should_continue(response->handle)) { - sfetch_continue(response->handle); - } - } - } - - - CHUNK SIZE AND HTTP COMPRESSION - =============================== - TL;DR: for streaming scenarios, the provided chunk-size must be smaller - than the provided buffer-size because the web server may decide to - serve the data compressed and the chunk-size must be given in 'compressed - bytes' while the buffer receives 'uncompressed bytes'. It's not possible - in HTTP to query the uncompressed size for a compressed download until - that download has finished. - - With vanilla HTTP, it is not possible to query the actual size of a file - without downloading the entire file first (the Content-Length response - header only provides the compressed size). Furthermore, for HTTP - range-requests, the range is given on the compressed data, not the - uncompressed data. So if the web server decides to server the data - compressed, the content-length and range-request parameters don't - correspond to the uncompressed data that's arriving in the sokol-fetch - buffers, and there's no way from JS or WASM to either force uncompressed - downloads (e.g. by setting the Accept-Encoding field), or access the - compressed data. - - This has some implications for sokol_fetch.h, most notably that buffers - can't be provided in the exactly right size, because that size can't - be queried from HTTP before the data is actually downloaded. - - When downloading whole files at once, it is basically expected that you - know the maximum files size upfront through other means (for instance - through a separate meta-data-file which contains the file sizes and - other meta-data for each file that needs to be loaded). - - For streaming downloads the situation is a bit more complicated. These - use HTTP range-requests, and those ranges are defined on the (potentially) - compressed data which the JS/WASM side doesn't have access to. However, - the JS/WASM side only ever sees the uncompressed data, and it's not possible - to query the uncompressed size of a range request before that range request - has finished. - - If the provided buffer is too small to contain the uncompressed data, - the request will fail with error code SFETCH_ERROR_BUFFER_TOO_SMALL. - - - CHANNELS AND LANES - ================== - Channels and lanes are (somewhat artificial) concepts to manage - parallelization, prioritization and rate-limiting. - - Channels can be used to parallelize message processing for better 'pipeline - throughput', and to prioritize requests: user-code could reserve one - channel for streaming downloads which need to run in parallel to other - requests, another channel for "regular" downloads and yet another - high-priority channel which would only be used for small files which need - to start loading immediately. - - Each channel comes with its own IO thread and message queues for pumping - messages in and out of the thread. The channel where a request is - processed is selected manually when sending a message: - - sfetch_send(&(sfetch_request_t){ - .path = "my_file.txt", - .callback = my_response_callback, - .channel = 2 - }); - - The number of channels is configured at startup in sfetch_setup() and - cannot be changed afterwards. - - Channels are completely separate from each other, and a request will - never "hop" from one channel to another. - - Each channel consists of a fixed number of "lanes" for automatic rate - limiting: - - When a request is sent to a channel via sfetch_send(), a "free lane" will - be picked and assigned to the request. The request will occupy this lane - for its entire life time (also while it is paused). If all lanes of a - channel are currently occupied, new requests will need to wait until a - lane becomes unoccupied. - - Since the number of channels and lanes is known upfront, it is guaranteed - that there will never be more than "num_channels * num_lanes" requests - in flight at any one time. - - This guarantee eliminates unexpected load- and memory-spikes when - many requests are sent in very short time, and it allows to pre-allocate - a fixed number of memory buffers which can be reused for the entire - "lifetime" of a sokol-fetch context. - - In the most simple scenario - when a maximum file size is known - buffers - can be statically allocated like this: - - uint8_t buffer[NUM_CHANNELS][NUM_LANES][MAX_FILE_SIZE]; - - Then in the user callback pick a buffer by channel and lane, - and associate it with the request like this: - - void response_callback(const sfetch_response_t* response) { - if (response->dispatched) { - void* ptr = buffer[response->channel][response->lane]; - sfetch_bind_buffer(response->handle, ptr, MAX_FILE_SIZE); - } - ... - } - - - NOTES ON OPTIMIZING PIPELINE LATENCY AND THROUGHPUT - =================================================== - With the default configuration of 1 channel and 1 lane per channel, - sokol_fetch.h will appear to have a shockingly bad loading performance - if several files are loaded. - - This has two reasons: - - (1) all parallelization when loading data has been disabled. A new - request will only be processed, when the last request has finished. - - (2) every invocation of the response-callback adds one frame of latency - to the request, because callbacks will only be called from within - sfetch_dowork() - - sokol-fetch takes a few shortcuts to improve step (2) and reduce - the 'inherent latency' of a request: - - - if a buffer is provided upfront, the response-callback won't be - called in the DISPATCHED state, but start right with the FETCHED state - where data has already been loaded into the buffer - - - there is no separate CLOSED state where the callback is invoked - separately when loading has finished (or the request has failed), - instead the finished and failed flags will be set as part of - the last FETCHED invocation - - This means providing a big-enough buffer to fit the entire file is the - best case, the response callback will only be called once, ideally in - the next frame (or two calls to sfetch_dowork()). - - If no buffer is provided upfront, one frame of latency is added because - the response callback needs to be invoked in the DISPATCHED state so that - the user code can bind a buffer. - - This means the best case for a request without an upfront-provided - buffer is 2 frames (or 3 calls to sfetch_dowork()). - - That's about what can be done to improve the latency for a single request, - but the really important step is to improve overall throughput. If you - need to load thousands of files you don't want that to be completely - serialized. - - The most important action to increase throughput is to increase the - number of lanes per channel. This defines how many requests can be - 'in flight' on a single channel at the same time. The guiding decision - factor for how many lanes you can "afford" is the memory size you want - to set aside for buffers. Each lane needs its own buffer so that - the data loaded for one request doesn't scribble over the data - loaded for another request. - - Here's a simple example of sending 4 requests without upfront buffer - on a channel with 1, 2 and 4 lanes, each line is one frame: - - 1 LANE (8 frames): - Lane 0: - ------------- - REQ 0 DISPATCHED - REQ 0 FETCHED - REQ 1 DISPATCHED - REQ 1 FETCHED - REQ 2 DISPATCHED - REQ 2 FETCHED - REQ 3 DISPATCHED - REQ 3 FETCHED - - Note how the request don't overlap, so they can all use the same buffer. - - 2 LANES (4 frames): - Lane 0: Lane 1: - ------------------------------------ - REQ 0 DISPATCHED REQ 1 DISPATCHED - REQ 0 FETCHED REQ 1 FETCHED - REQ 2 DISPATCHED REQ 3 DISPATCHED - REQ 2 FETCHED REQ 3 FETCHED - - This reduces the overall time to 4 frames, but now you need 2 buffers so - that requests don't scribble over each other. - - 4 LANES (2 frames): - Lane 0: Lane 1: Lane 2: Lane 3: - ---------------------------------------------------------------------------- - REQ 0 DISPATCHED REQ 1 DISPATCHED REQ 2 DISPATCHED REQ 3 DISPATCHED - REQ 0 FETCHED REQ 1 FETCHED REQ 2 FETCHED REQ 3 FETCHED - - Now we're down to the same 'best-case' latency as sending a single - request. - - Apart from the memory requirements for the streaming buffers (which is - under your control), you can be generous with the number of lanes, - they don't add any processing overhead. - - The last option for tweaking latency and throughput is channels. Each - channel works independently from other channels, so while one - channel is busy working through a large number of requests (or one - very long streaming download), you can set aside a high-priority channel - for requests that need to start as soon as possible. - - On platforms with threading support, each channel runs on its own - thread, but this is mainly an implementation detail to work around - the blocking traditional file IO functions, not for performance reasons. - - - 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); - } - - ... - sfetch_setup(&(sfetch_desc_t){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ..., - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_fetch.h - itself though, not any allocations in OS libraries. - - Memory allocation will only happen on the same thread where sfetch_setup() - was called, so you don't need to worry about thread-safety. - - - 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" - - sfetch_setup(&(sfetch_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. 'sfetch' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SFETCH_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_fetch.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-fetch like this: - - sfetch_setup(&(sfetch_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. - - - FUTURE PLANS / V2.0 IDEA DUMP - ============================= - - An optional polling API (as alternative to callback API) - - Move buffer-management into the API? The "manual management" - can be quite tricky especially for dynamic allocation scenarios, - API support for buffer management would simplify cases like - preventing that requests scribble over each other's buffers, or - an automatic garbage collection for dynamically allocated buffers, - or automatically falling back to dynamic allocation if static - buffers aren't big enough. - - Pluggable request handlers to load data from other "sources" - (especially HTTP downloads on native platforms via e.g. libcurl - would be useful) - - I'm currently not happy how the user-data block is handled, this - should getting and updating the user-data should be wrapped by - API functions (similar to bind/unbind buffer) - - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2019 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. -*/ -#define SOKOL_FETCH_INCLUDED (1) -#include // size_t -#include -#include - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_FETCH_API_DECL) -#define SOKOL_FETCH_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_FETCH_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_FETCH_IMPL) -#define SOKOL_FETCH_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_FETCH_API_DECL __declspec(dllimport) -#else -#define SOKOL_FETCH_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - sfetch_log_item_t - - Log items are defined via X-Macros, and expanded to an - enum 'sfetch_log_item', and in debug mode only, - corresponding strings. - - Used as parameter in the logging callback. -*/ -#define _SFETCH_LOG_ITEMS \ - _SFETCH_LOGITEM_XMACRO(OK, "Ok") \ - _SFETCH_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SFETCH_LOGITEM_XMACRO(FILE_PATH_UTF8_DECODING_FAILED, "failed converting file path from UTF8 to wide") \ - _SFETCH_LOGITEM_XMACRO(SEND_QUEUE_FULL, "send queue full (adjust via sfetch_desc_t.max_requests)") \ - _SFETCH_LOGITEM_XMACRO(REQUEST_CHANNEL_INDEX_TOO_BIG, "channel index too big (adjust via sfetch_desc_t.num_channels)") \ - _SFETCH_LOGITEM_XMACRO(REQUEST_PATH_IS_NULL, "file path is nullptr (sfetch_request_t.path)") \ - _SFETCH_LOGITEM_XMACRO(REQUEST_PATH_TOO_LONG, "file path is too long (SFETCH_MAX_PATH)") \ - _SFETCH_LOGITEM_XMACRO(REQUEST_CALLBACK_MISSING, "no callback provided (sfetch_request_t.callback)") \ - _SFETCH_LOGITEM_XMACRO(REQUEST_CHUNK_SIZE_GREATER_BUFFER_SIZE, "chunk size is greater buffer size (sfetch_request_t.chunk_size vs .buffer.size)") \ - _SFETCH_LOGITEM_XMACRO(REQUEST_USERDATA_PTR_IS_SET_BUT_USERDATA_SIZE_IS_NULL, "user data ptr is set but user data size is null (sfetch_request_t.user_data.ptr vs .size)") \ - _SFETCH_LOGITEM_XMACRO(REQUEST_USERDATA_PTR_IS_NULL_BUT_USERDATA_SIZE_IS_NOT, "user data ptr is null but size is not (sfetch_request_t.user_data.ptr vs .size)") \ - _SFETCH_LOGITEM_XMACRO(REQUEST_USERDATA_SIZE_TOO_BIG, "user data size too big (see SFETCH_MAX_USERDATA_UINT64)") \ - _SFETCH_LOGITEM_XMACRO(CLAMPING_NUM_CHANNELS_TO_MAX_CHANNELS, "clamping num channels to SFETCH_MAX_CHANNELS") \ - _SFETCH_LOGITEM_XMACRO(REQUEST_POOL_EXHAUSTED, "request pool exhausted (tweak via sfetch_desc_t.max_requests)") \ - -#define _SFETCH_LOGITEM_XMACRO(item,msg) SFETCH_LOGITEM_##item, -typedef enum sfetch_log_item_t { - _SFETCH_LOG_ITEMS -} sfetch_log_item_t; -#undef _SFETCH_LOGITEM_XMACRO - -/* - sfetch_logger_t - - Used in sfetch_desc_t to provide a custom logging and error reporting - callback to sokol-fetch. -*/ -typedef struct sfetch_logger_t { - void (*func)( - const char* tag, // always "sfetch" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SFETCH_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_fetch.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} sfetch_logger_t; - -/* - sfetch_range_t - - A pointer-size pair struct to pass memory ranges into and out of sokol-fetch. - When initialized from a value type (array or struct) you can use the - SFETCH_RANGE() helper macro to build an sfetch_range_t struct. -*/ -typedef struct sfetch_range_t { - const void* ptr; - size_t size; -} sfetch_range_t; - -// disabling this for every includer isn't great, but the warnings are also quite pointless -#if defined(_MSC_VER) -#pragma warning(disable:4221) // /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' -#pragma warning(disable:4204) // VS2015: nonstandard extension used: non-constant aggregate initializer -#endif -#if defined(__cplusplus) -#define SFETCH_RANGE(x) sfetch_range_t{ &x, sizeof(x) } -#else -#define SFETCH_RANGE(x) (sfetch_range_t){ &x, sizeof(x) } -#endif - -/* - sfetch_allocator_t - - Used in sfetch_desc_t to provide custom memory-alloc and -free functions - to sokol_fetch.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). -*/ -typedef struct sfetch_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sfetch_allocator_t; - -/* configuration values for sfetch_setup() */ -typedef struct sfetch_desc_t { - uint32_t max_requests; // max number of active requests across all channels (default: 128) - uint32_t num_channels; // number of channels to fetch requests in parallel (default: 1) - uint32_t num_lanes; // max number of requests active on the same channel (default: 1) - sfetch_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) - sfetch_logger_t logger; // optional log function overrides (default: NO LOGGING!) -} sfetch_desc_t; - -/* a request handle to identify an active fetch request, returned by sfetch_send() */ -typedef struct sfetch_handle_t { uint32_t id; } sfetch_handle_t; - -/* error codes */ -typedef enum sfetch_error_t { - SFETCH_ERROR_NO_ERROR, - SFETCH_ERROR_FILE_NOT_FOUND, - SFETCH_ERROR_NO_BUFFER, - SFETCH_ERROR_BUFFER_TOO_SMALL, - SFETCH_ERROR_UNEXPECTED_EOF, - SFETCH_ERROR_INVALID_HTTP_STATUS, - SFETCH_ERROR_CANCELLED -} sfetch_error_t; - -/* the response struct passed to the response callback */ -typedef struct sfetch_response_t { - sfetch_handle_t handle; // request handle this response belongs to - bool dispatched; // true when request is in DISPATCHED state (lane has been assigned) - bool fetched; // true when request is in FETCHED state (fetched data is available) - bool paused; // request is currently in paused state - bool finished; // this is the last response for this request - bool failed; // request has failed (always set together with 'finished') - bool cancelled; // request was cancelled (always set together with 'finished') - sfetch_error_t error_code; // more detailed error code when failed is true - uint32_t channel; // the channel which processes this request - uint32_t lane; // the lane this request occupies on its channel - const char* path; // the original filesystem path of the request - void* user_data; // pointer to read/write user-data area - uint32_t data_offset; // current offset of fetched data chunk in the overall file data - sfetch_range_t data; // the fetched data as ptr/size pair (data.ptr == buffer.ptr, data.size <= buffer.size) - sfetch_range_t buffer; // the user-provided buffer which holds the fetched data -} sfetch_response_t; - -/* request parameters passed to sfetch_send() */ -typedef struct sfetch_request_t { - uint32_t channel; // index of channel this request is assigned to (default: 0) - const char* path; // filesystem path or HTTP URL (required) - void (*callback) (const sfetch_response_t*); // response callback function pointer (required) - uint32_t chunk_size; // number of bytes to load per stream-block (optional) - sfetch_range_t buffer; // a memory buffer where the data will be loaded into (optional) - sfetch_range_t user_data; // ptr/size of a POD user data block which will be memcpy'd (optional) -} sfetch_request_t; - -/* setup sokol-fetch (can be called on multiple threads) */ -SOKOL_FETCH_API_DECL void sfetch_setup(const sfetch_desc_t* desc); -/* discard a sokol-fetch context */ -SOKOL_FETCH_API_DECL void sfetch_shutdown(void); -/* return true if sokol-fetch has been setup */ -SOKOL_FETCH_API_DECL bool sfetch_valid(void); -/* get the desc struct that was passed to sfetch_setup() */ -SOKOL_FETCH_API_DECL sfetch_desc_t sfetch_desc(void); -/* return the max userdata size in number of bytes (SFETCH_MAX_USERDATA_UINT64 * sizeof(uint64_t)) */ -SOKOL_FETCH_API_DECL int sfetch_max_userdata_bytes(void); -/* return the value of the SFETCH_MAX_PATH implementation config value */ -SOKOL_FETCH_API_DECL int sfetch_max_path(void); - -/* send a fetch-request, get handle to request back */ -SOKOL_FETCH_API_DECL sfetch_handle_t sfetch_send(const sfetch_request_t* request); -/* return true if a handle is valid *and* the request is alive */ -SOKOL_FETCH_API_DECL bool sfetch_handle_valid(sfetch_handle_t h); -/* do per-frame work, moves requests into and out of IO threads, and invokes response-callbacks */ -SOKOL_FETCH_API_DECL void sfetch_dowork(void); - -/* bind a data buffer to a request (request must not currently have a buffer bound, must be called from response callback */ -SOKOL_FETCH_API_DECL void sfetch_bind_buffer(sfetch_handle_t h, sfetch_range_t buffer); -/* clear the 'buffer binding' of a request, returns previous buffer pointer (can be 0), must be called from response callback */ -SOKOL_FETCH_API_DECL void* sfetch_unbind_buffer(sfetch_handle_t h); -/* cancel a request that's in flight (will call response callback with .cancelled + .finished) */ -SOKOL_FETCH_API_DECL void sfetch_cancel(sfetch_handle_t h); -/* pause a request (will call response callback each frame with .paused) */ -SOKOL_FETCH_API_DECL void sfetch_pause(sfetch_handle_t h); -/* continue a paused request */ -SOKOL_FETCH_API_DECL void sfetch_continue(sfetch_handle_t h); - -#ifdef __cplusplus -} /* extern "C" */ - -/* reference-based equivalents for c++ */ -inline void sfetch_setup(const sfetch_desc_t& desc) { return sfetch_setup(&desc); } -inline sfetch_handle_t sfetch_send(const sfetch_request_t& request) { return sfetch_send(&request); } - -#endif -#endif // SOKOL_FETCH_INCLUDED - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_FETCH_IMPL -#define SOKOL_FETCH_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sfetch_desc_t.allocator to override memory allocation functions" -#endif - -#include /* malloc, free */ -#include /* memset, memcpy */ - -#ifndef SFETCH_MAX_PATH -#define SFETCH_MAX_PATH (1024) -#endif -#ifndef SFETCH_MAX_USERDATA_UINT64 -#define SFETCH_MAX_USERDATA_UINT64 (16) -#endif -#ifndef SFETCH_MAX_CHANNELS -#define SFETCH_MAX_CHANNELS (16) -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -#ifndef _SOKOL_UNUSED - #define _SOKOL_UNUSED(x) (void)(x) -#endif - -#if defined(__EMSCRIPTEN__) - #include - #define _SFETCH_PLATFORM_EMSCRIPTEN (1) - #define _SFETCH_PLATFORM_WINDOWS (0) - #define _SFETCH_PLATFORM_POSIX (0) - #define _SFETCH_HAS_THREADS (0) -#elif defined(_WIN32) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - #ifndef NOMINMAX - #define NOMINMAX - #endif - #include - #define _SFETCH_PLATFORM_WINDOWS (1) - #define _SFETCH_PLATFORM_EMSCRIPTEN (0) - #define _SFETCH_PLATFORM_POSIX (0) - #define _SFETCH_HAS_THREADS (1) -#else - #include - #include /* fopen, fread, fseek, fclose */ - #define _SFETCH_PLATFORM_POSIX (1) - #define _SFETCH_PLATFORM_EMSCRIPTEN (0) - #define _SFETCH_PLATFORM_WINDOWS (0) - #define _SFETCH_HAS_THREADS (1) -#endif - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4724) // potential mod by 0 -#endif - -// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██████ ██ ██ ██ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██████ ██████ ██ ███████ -// -// >>structs -typedef struct _sfetch_path_t { - char buf[SFETCH_MAX_PATH]; -} _sfetch_path_t; - -/* a thread with incoming and outgoing message queue syncing */ -#if _SFETCH_PLATFORM_POSIX -typedef struct { - pthread_t thread; - pthread_cond_t incoming_cond; - pthread_mutex_t incoming_mutex; - pthread_mutex_t outgoing_mutex; - pthread_mutex_t running_mutex; - pthread_mutex_t stop_mutex; - bool stop_requested; - bool valid; -} _sfetch_thread_t; -#elif _SFETCH_PLATFORM_WINDOWS -typedef struct { - HANDLE thread; - HANDLE incoming_event; - CRITICAL_SECTION incoming_critsec; - CRITICAL_SECTION outgoing_critsec; - CRITICAL_SECTION running_critsec; - CRITICAL_SECTION stop_critsec; - bool stop_requested; - bool valid; -} _sfetch_thread_t; -#endif - -/* file handle abstraction */ -#if _SFETCH_PLATFORM_POSIX -typedef FILE* _sfetch_file_handle_t; -#define _SFETCH_INVALID_FILE_HANDLE (0) -typedef void*(*_sfetch_thread_func_t)(void*); -#elif _SFETCH_PLATFORM_WINDOWS -typedef HANDLE _sfetch_file_handle_t; -#define _SFETCH_INVALID_FILE_HANDLE (INVALID_HANDLE_VALUE) -typedef LPTHREAD_START_ROUTINE _sfetch_thread_func_t; -#endif - -/* user-side per-request state */ -typedef struct { - bool pause; /* switch item to PAUSED state if true */ - bool cont; /* switch item back to FETCHING if true */ - bool cancel; /* cancel the request, switch into FAILED state */ - /* transfer IO => user thread */ - uint32_t fetched_offset; /* number of bytes fetched so far */ - uint32_t fetched_size; /* size of last fetched chunk */ - sfetch_error_t error_code; - bool finished; - /* user thread only */ - size_t user_data_size; - uint64_t user_data[SFETCH_MAX_USERDATA_UINT64]; -} _sfetch_item_user_t; - -/* thread-side per-request state */ -typedef struct { - /* transfer IO => user thread */ - uint32_t fetched_offset; - uint32_t fetched_size; - sfetch_error_t error_code; - bool failed; - bool finished; - /* IO thread only */ - #if _SFETCH_PLATFORM_EMSCRIPTEN - uint32_t http_range_offset; - #else - _sfetch_file_handle_t file_handle; - #endif - uint32_t content_size; -} _sfetch_item_thread_t; - -/* a request goes through the following states, ping-ponging between IO and user thread */ -typedef enum _sfetch_state_t { - _SFETCH_STATE_INITIAL, /* internal: request has just been initialized */ - _SFETCH_STATE_ALLOCATED, /* internal: request has been allocated from internal pool */ - _SFETCH_STATE_DISPATCHED, /* user thread: request has been dispatched to its IO channel */ - _SFETCH_STATE_FETCHING, /* IO thread: waiting for data to be fetched */ - _SFETCH_STATE_FETCHED, /* user thread: fetched data available */ - _SFETCH_STATE_PAUSED, /* user thread: request has been paused via sfetch_pause() */ - _SFETCH_STATE_FAILED, /* user thread: follow state or FETCHING if something went wrong */ -} _sfetch_state_t; - -/* an internal request item */ -#define _SFETCH_INVALID_LANE (0xFFFFFFFF) -typedef struct { - sfetch_handle_t handle; - _sfetch_state_t state; - uint32_t channel; - uint32_t lane; - uint32_t chunk_size; - void (*callback) (const sfetch_response_t*); - sfetch_range_t buffer; - - /* updated by IO-thread, off-limits to user thread */ - _sfetch_item_thread_t thread; - - /* accessible by user-thread, off-limits to IO thread */ - _sfetch_item_user_t user; - - /* big stuff at the end */ - _sfetch_path_t path; -} _sfetch_item_t; - -/* a pool of internal per-request items */ -typedef struct { - uint32_t size; - uint32_t free_top; - _sfetch_item_t* items; - uint32_t* free_slots; - uint32_t* gen_ctrs; - bool valid; -} _sfetch_pool_t; - -/* a ringbuffer for pool-slot ids */ -typedef struct { - uint32_t head; - uint32_t tail; - uint32_t num; - uint32_t* buf; -} _sfetch_ring_t; - -/* an IO channel with its own IO thread */ -struct _sfetch_t; -typedef struct { - struct _sfetch_t* ctx; // back-pointer to thread-local _sfetch state pointer, since this isn't accessible from the IO threads - _sfetch_ring_t free_lanes; - _sfetch_ring_t user_sent; - _sfetch_ring_t user_incoming; - _sfetch_ring_t user_outgoing; - #if _SFETCH_HAS_THREADS - _sfetch_ring_t thread_incoming; - _sfetch_ring_t thread_outgoing; - _sfetch_thread_t thread; - #endif - void (*request_handler)(struct _sfetch_t* ctx, uint32_t slot_id); - bool valid; -} _sfetch_channel_t; - -/* the sfetch global state */ -typedef struct _sfetch_t { - bool setup; - bool valid; - bool in_callback; - sfetch_desc_t desc; - _sfetch_pool_t pool; - _sfetch_channel_t chn[SFETCH_MAX_CHANNELS]; -} _sfetch_t; -#if _SFETCH_HAS_THREADS -#if defined(_MSC_VER) -static __declspec(thread) _sfetch_t* _sfetch; -#else -static __thread _sfetch_t* _sfetch; -#endif -#else -static _sfetch_t* _sfetch; -#endif -#define _sfetch_def(val, def) (((val) == 0) ? (def) : (val)) - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SFETCH_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _sfetch_log_messages[] = { - _SFETCH_LOG_ITEMS -}; -#undef _SFETCH_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SFETCH_PANIC(code) _sfetch_log(SFETCH_LOGITEM_ ##code, 0, __LINE__) -#define _SFETCH_ERROR(code) _sfetch_log(SFETCH_LOGITEM_ ##code, 1, __LINE__) -#define _SFETCH_WARN(code) _sfetch_log(SFETCH_LOGITEM_ ##code, 2, __LINE__) -#define _SFETCH_INFO(code) _sfetch_log(SFETCH_LOGITEM_ ##code, 3, __LINE__) - -static void _sfetch_log(sfetch_log_item_t log_item, uint32_t log_level, uint32_t line_nr) { - if (_sfetch->desc.logger.func) { - #if defined(SOKOL_DEBUG) - const char* filename = __FILE__; - const char* message = _sfetch_log_messages[log_item]; - #else - const char* filename = 0; - const char* message = 0; - #endif - _sfetch->desc.logger.func("sfetch", log_level, log_item, message, line_nr, filename, _sfetch->desc.logger.user_data); - } - else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -_SOKOL_PRIVATE void _sfetch_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -_SOKOL_PRIVATE void* _sfetch_malloc_with_allocator(const sfetch_allocator_t* allocator, size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (allocator->alloc_fn) { - ptr = allocator->alloc_fn(size, allocator->user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SFETCH_PANIC(MALLOC_FAILED); - } - return ptr; -} - -_SOKOL_PRIVATE void* _sfetch_malloc(size_t size) { - return _sfetch_malloc_with_allocator(&_sfetch->desc.allocator, size); -} - -_SOKOL_PRIVATE void* _sfetch_malloc_clear(size_t size) { - void* ptr = _sfetch_malloc(size); - _sfetch_clear(ptr, size); - return ptr; -} - -_SOKOL_PRIVATE void _sfetch_free(void* ptr) { - if (_sfetch->desc.allocator.free_fn) { - _sfetch->desc.allocator.free_fn(ptr, _sfetch->desc.allocator.user_data); - } else { - free(ptr); - } -} - -_SOKOL_PRIVATE _sfetch_t* _sfetch_ctx(void) { - return _sfetch; -} - -_SOKOL_PRIVATE void _sfetch_path_copy(_sfetch_path_t* dst, const char* src) { - SOKOL_ASSERT(dst); - if (src && (strlen(src) < SFETCH_MAX_PATH)) { - #if defined(_MSC_VER) - strncpy_s(dst->buf, SFETCH_MAX_PATH, src, (SFETCH_MAX_PATH-1)); - #else - strncpy(dst->buf, src, SFETCH_MAX_PATH); - #endif - dst->buf[SFETCH_MAX_PATH-1] = 0; - } - else { - _sfetch_clear(dst->buf, SFETCH_MAX_PATH); - } -} - -_SOKOL_PRIVATE _sfetch_path_t _sfetch_path_make(const char* str) { - _sfetch_path_t res; - _sfetch_path_copy(&res, str); - return res; -} - -// ███ ███ ███████ ███████ ███████ █████ ██████ ███████ ██████ ██ ██ ███████ ██ ██ ███████ -// ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ███████ ███████ ███████ ██ ███ █████ ██ ██ ██ ██ █████ ██ ██ █████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ▄▄ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ███████ ███████ ██ ██ ██████ ███████ ██████ ██████ ███████ ██████ ███████ -// ▀▀ -// >>message queue -_SOKOL_PRIVATE uint32_t _sfetch_ring_wrap(const _sfetch_ring_t* rb, uint32_t i) { - return i % rb->num; -} - -_SOKOL_PRIVATE void _sfetch_ring_discard(_sfetch_ring_t* rb) { - SOKOL_ASSERT(rb); - if (rb->buf) { - _sfetch_free(rb->buf); - rb->buf = 0; - } - rb->head = 0; - rb->tail = 0; - rb->num = 0; -} - -_SOKOL_PRIVATE bool _sfetch_ring_init(_sfetch_ring_t* rb, uint32_t num_slots) { - SOKOL_ASSERT(rb && (num_slots > 0)); - SOKOL_ASSERT(0 == rb->buf); - rb->head = 0; - rb->tail = 0; - /* one slot reserved to detect full vs empty */ - rb->num = num_slots + 1; - const size_t queue_size = rb->num * sizeof(sfetch_handle_t); - rb->buf = (uint32_t*) _sfetch_malloc_clear(queue_size); - if (rb->buf) { - return true; - } - else { - _sfetch_ring_discard(rb); - return false; - } -} - -_SOKOL_PRIVATE bool _sfetch_ring_full(const _sfetch_ring_t* rb) { - SOKOL_ASSERT(rb && rb->buf); - return _sfetch_ring_wrap(rb, rb->head + 1) == rb->tail; -} - -_SOKOL_PRIVATE bool _sfetch_ring_empty(const _sfetch_ring_t* rb) { - SOKOL_ASSERT(rb && rb->buf); - return rb->head == rb->tail; -} - -_SOKOL_PRIVATE uint32_t _sfetch_ring_count(const _sfetch_ring_t* rb) { - SOKOL_ASSERT(rb && rb->buf); - uint32_t count; - if (rb->head >= rb->tail) { - count = rb->head - rb->tail; - } - else { - count = (rb->head + rb->num) - rb->tail; - } - SOKOL_ASSERT(count < rb->num); - return count; -} - -_SOKOL_PRIVATE void _sfetch_ring_enqueue(_sfetch_ring_t* rb, uint32_t slot_id) { - SOKOL_ASSERT(rb && rb->buf); - SOKOL_ASSERT(!_sfetch_ring_full(rb)); - SOKOL_ASSERT(rb->head < rb->num); - rb->buf[rb->head] = slot_id; - rb->head = _sfetch_ring_wrap(rb, rb->head + 1); -} - -_SOKOL_PRIVATE uint32_t _sfetch_ring_dequeue(_sfetch_ring_t* rb) { - SOKOL_ASSERT(rb && rb->buf); - SOKOL_ASSERT(!_sfetch_ring_empty(rb)); - SOKOL_ASSERT(rb->tail < rb->num); - uint32_t slot_id = rb->buf[rb->tail]; - rb->tail = _sfetch_ring_wrap(rb, rb->tail + 1); - return slot_id; -} - -_SOKOL_PRIVATE uint32_t _sfetch_ring_peek(const _sfetch_ring_t* rb, uint32_t index) { - SOKOL_ASSERT(rb && rb->buf); - SOKOL_ASSERT(!_sfetch_ring_empty(rb)); - SOKOL_ASSERT(index < _sfetch_ring_count(rb)); - uint32_t rb_index = _sfetch_ring_wrap(rb, rb->tail + index); - return rb->buf[rb_index]; -} - -// ██████ ███████ ██████ ██ ██ ███████ ███████ ████████ ██████ ██████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ █████ ██ ██ ██ ██ █████ ███████ ██ ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ▄▄ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██████ ██████ ███████ ███████ ██ ██ ██████ ██████ ███████ -// ▀▀ -// >>request pool -_SOKOL_PRIVATE uint32_t _sfetch_make_id(uint32_t index, uint32_t gen_ctr) { - return (gen_ctr<<16) | (index & 0xFFFF); -} - -_SOKOL_PRIVATE sfetch_handle_t _sfetch_make_handle(uint32_t slot_id) { - sfetch_handle_t h; - h.id = slot_id; - return h; -} - -_SOKOL_PRIVATE uint32_t _sfetch_slot_index(uint32_t slot_id) { - return slot_id & 0xFFFF; -} - -_SOKOL_PRIVATE void _sfetch_item_init(_sfetch_item_t* item, uint32_t slot_id, const sfetch_request_t* request) { - SOKOL_ASSERT(item && (0 == item->handle.id)); - SOKOL_ASSERT(request && request->path); - _sfetch_clear(item, sizeof(_sfetch_item_t)); - item->handle.id = slot_id; - item->state = _SFETCH_STATE_INITIAL; - item->channel = request->channel; - item->chunk_size = request->chunk_size; - item->lane = _SFETCH_INVALID_LANE; - item->callback = request->callback; - item->buffer = request->buffer; - item->path = _sfetch_path_make(request->path); - #if !_SFETCH_PLATFORM_EMSCRIPTEN - item->thread.file_handle = _SFETCH_INVALID_FILE_HANDLE; - #endif - if (request->user_data.ptr && - (request->user_data.size > 0) && - (request->user_data.size <= (SFETCH_MAX_USERDATA_UINT64*8))) - { - item->user.user_data_size = request->user_data.size; - memcpy(item->user.user_data, request->user_data.ptr, request->user_data.size); - } -} - -_SOKOL_PRIVATE void _sfetch_item_discard(_sfetch_item_t* item) { - SOKOL_ASSERT(item && (0 != item->handle.id)); - _sfetch_clear(item, sizeof(_sfetch_item_t)); -} - -_SOKOL_PRIVATE void _sfetch_pool_discard(_sfetch_pool_t* pool) { - SOKOL_ASSERT(pool); - if (pool->free_slots) { - _sfetch_free(pool->free_slots); - pool->free_slots = 0; - } - if (pool->gen_ctrs) { - _sfetch_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - } - if (pool->items) { - _sfetch_free(pool->items); - pool->items = 0; - } - pool->size = 0; - pool->free_top = 0; - pool->valid = false; -} - -_SOKOL_PRIVATE bool _sfetch_pool_init(_sfetch_pool_t* pool, uint32_t num_items) { - SOKOL_ASSERT(pool && (num_items > 0) && (num_items < ((1<<16)-1))); - SOKOL_ASSERT(0 == pool->items); - /* NOTE: item slot 0 is reserved for the special "invalid" item index 0*/ - pool->size = num_items + 1; - pool->free_top = 0; - const size_t items_size = pool->size * sizeof(_sfetch_item_t); - pool->items = (_sfetch_item_t*) _sfetch_malloc_clear(items_size); - /* generation counters indexable by pool slot index, slot 0 is reserved */ - const size_t gen_ctrs_size = sizeof(uint32_t) * pool->size; - pool->gen_ctrs = (uint32_t*) _sfetch_malloc_clear(gen_ctrs_size); - SOKOL_ASSERT(pool->gen_ctrs); - /* NOTE: it's not a bug to only reserve num_items here */ - const size_t free_slots_size = num_items * sizeof(int); - pool->free_slots = (uint32_t*) _sfetch_malloc_clear(free_slots_size); - if (pool->items && pool->free_slots) { - /* never allocate the 0-th item, this is the reserved 'invalid item' */ - for (uint32_t i = pool->size - 1; i >= 1; i--) { - pool->free_slots[pool->free_top++] = i; - } - pool->valid = true; - } - else { - /* allocation error */ - _sfetch_pool_discard(pool); - } - return pool->valid; -} - -_SOKOL_PRIVATE uint32_t _sfetch_pool_item_alloc(_sfetch_pool_t* pool, const sfetch_request_t* request) { - SOKOL_ASSERT(pool && pool->valid); - if (pool->free_top > 0) { - uint32_t slot_index = pool->free_slots[--pool->free_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - uint32_t slot_id = _sfetch_make_id(slot_index, ++pool->gen_ctrs[slot_index]); - _sfetch_item_init(&pool->items[slot_index], slot_id, request); - pool->items[slot_index].state = _SFETCH_STATE_ALLOCATED; - return slot_id; - } - else { - /* pool exhausted, return the 'invalid handle' */ - return _sfetch_make_id(0, 0); - } -} - -_SOKOL_PRIVATE void _sfetch_pool_item_free(_sfetch_pool_t* pool, uint32_t slot_id) { - SOKOL_ASSERT(pool && pool->valid); - uint32_t slot_index = _sfetch_slot_index(slot_id); - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - SOKOL_ASSERT(pool->items[slot_index].handle.id == slot_id); - #if defined(SOKOL_DEBUG) - /* debug check against double-free */ - for (uint32_t i = 0; i < pool->free_top; i++) { - SOKOL_ASSERT(pool->free_slots[i] != slot_index); - } - #endif - _sfetch_item_discard(&pool->items[slot_index]); - pool->free_slots[pool->free_top++] = slot_index; - SOKOL_ASSERT(pool->free_top <= (pool->size - 1)); -} - -/* return pointer to item by handle without matching id check */ -_SOKOL_PRIVATE _sfetch_item_t* _sfetch_pool_item_at(_sfetch_pool_t* pool, uint32_t slot_id) { - SOKOL_ASSERT(pool && pool->valid); - uint32_t slot_index = _sfetch_slot_index(slot_id); - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return &pool->items[slot_index]; -} - -/* return pointer to item by handle with matching id check */ -_SOKOL_PRIVATE _sfetch_item_t* _sfetch_pool_item_lookup(_sfetch_pool_t* pool, uint32_t slot_id) { - SOKOL_ASSERT(pool && pool->valid); - if (0 != slot_id) { - _sfetch_item_t* item = _sfetch_pool_item_at(pool, slot_id); - if (item->handle.id == slot_id) { - return item; - } - } - return 0; -} - -// ██████ ██████ ███████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ███████ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ███████ ██ ██ ██ -// -// >>posix -#if _SFETCH_PLATFORM_POSIX -_SOKOL_PRIVATE _sfetch_file_handle_t _sfetch_file_open(const _sfetch_path_t* path) { - return fopen(path->buf, "rb"); -} - -_SOKOL_PRIVATE void _sfetch_file_close(_sfetch_file_handle_t h) { - fclose(h); -} - -_SOKOL_PRIVATE bool _sfetch_file_handle_valid(_sfetch_file_handle_t h) { - return h != _SFETCH_INVALID_FILE_HANDLE; -} - -_SOKOL_PRIVATE uint32_t _sfetch_file_size(_sfetch_file_handle_t h) { - fseek(h, 0, SEEK_END); - return (uint32_t) ftell(h); -} - -_SOKOL_PRIVATE bool _sfetch_file_read(_sfetch_file_handle_t h, uint32_t offset, uint32_t num_bytes, void* ptr) { - fseek(h, (long)offset, SEEK_SET); - return num_bytes == fread(ptr, 1, num_bytes, h); -} - -_SOKOL_PRIVATE bool _sfetch_thread_init(_sfetch_thread_t* thread, _sfetch_thread_func_t thread_func, void* thread_arg) { - SOKOL_ASSERT(thread && !thread->valid && !thread->stop_requested); - - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutex_init(&thread->incoming_mutex, &attr); - pthread_mutexattr_destroy(&attr); - - pthread_mutexattr_init(&attr); - pthread_mutex_init(&thread->outgoing_mutex, &attr); - pthread_mutexattr_destroy(&attr); - - pthread_mutexattr_init(&attr); - pthread_mutex_init(&thread->running_mutex, &attr); - pthread_mutexattr_destroy(&attr); - - pthread_mutexattr_init(&attr); - pthread_mutex_init(&thread->stop_mutex, &attr); - pthread_mutexattr_destroy(&attr); - - pthread_condattr_t cond_attr; - pthread_condattr_init(&cond_attr); - pthread_cond_init(&thread->incoming_cond, &cond_attr); - pthread_condattr_destroy(&cond_attr); - - /* FIXME: in debug mode, the threads should be named */ - pthread_mutex_lock(&thread->running_mutex); - int res = pthread_create(&thread->thread, 0, thread_func, thread_arg); - thread->valid = (0 == res); - pthread_mutex_unlock(&thread->running_mutex); - return thread->valid; -} - -_SOKOL_PRIVATE void _sfetch_thread_request_stop(_sfetch_thread_t* thread) { - pthread_mutex_lock(&thread->stop_mutex); - thread->stop_requested = true; - pthread_mutex_unlock(&thread->stop_mutex); -} - -_SOKOL_PRIVATE bool _sfetch_thread_stop_requested(_sfetch_thread_t* thread) { - pthread_mutex_lock(&thread->stop_mutex); - bool stop_requested = thread->stop_requested; - pthread_mutex_unlock(&thread->stop_mutex); - return stop_requested; -} - -_SOKOL_PRIVATE void _sfetch_thread_join(_sfetch_thread_t* thread) { - SOKOL_ASSERT(thread); - if (thread->valid) { - pthread_mutex_lock(&thread->incoming_mutex); - _sfetch_thread_request_stop(thread); - pthread_cond_signal(&thread->incoming_cond); - pthread_mutex_unlock(&thread->incoming_mutex); - pthread_join(thread->thread, 0); - thread->valid = false; - } - pthread_mutex_destroy(&thread->stop_mutex); - pthread_mutex_destroy(&thread->running_mutex); - pthread_mutex_destroy(&thread->incoming_mutex); - pthread_mutex_destroy(&thread->outgoing_mutex); - pthread_cond_destroy(&thread->incoming_cond); -} - -/* called when the thread-func is entered, this blocks the thread func until - the _sfetch_thread_t object is fully initialized -*/ -_SOKOL_PRIVATE void _sfetch_thread_entered(_sfetch_thread_t* thread) { - pthread_mutex_lock(&thread->running_mutex); -} - -/* called by the thread-func right before it is left */ -_SOKOL_PRIVATE void _sfetch_thread_leaving(_sfetch_thread_t* thread) { - pthread_mutex_unlock(&thread->running_mutex); -} - -_SOKOL_PRIVATE void _sfetch_thread_enqueue_incoming(_sfetch_thread_t* thread, _sfetch_ring_t* incoming, _sfetch_ring_t* src) { - /* called from user thread */ - SOKOL_ASSERT(thread && thread->valid); - SOKOL_ASSERT(incoming && incoming->buf); - SOKOL_ASSERT(src && src->buf); - if (!_sfetch_ring_empty(src)) { - pthread_mutex_lock(&thread->incoming_mutex); - while (!_sfetch_ring_full(incoming) && !_sfetch_ring_empty(src)) { - _sfetch_ring_enqueue(incoming, _sfetch_ring_dequeue(src)); - } - pthread_cond_signal(&thread->incoming_cond); - pthread_mutex_unlock(&thread->incoming_mutex); - } -} - -_SOKOL_PRIVATE uint32_t _sfetch_thread_dequeue_incoming(_sfetch_thread_t* thread, _sfetch_ring_t* incoming) { - /* called from thread function */ - SOKOL_ASSERT(thread && thread->valid); - SOKOL_ASSERT(incoming && incoming->buf); - pthread_mutex_lock(&thread->incoming_mutex); - while (_sfetch_ring_empty(incoming) && !thread->stop_requested) { - pthread_cond_wait(&thread->incoming_cond, &thread->incoming_mutex); - } - uint32_t item = 0; - if (!thread->stop_requested) { - item = _sfetch_ring_dequeue(incoming); - } - pthread_mutex_unlock(&thread->incoming_mutex); - return item; -} - -_SOKOL_PRIVATE bool _sfetch_thread_enqueue_outgoing(_sfetch_thread_t* thread, _sfetch_ring_t* outgoing, uint32_t item) { - /* called from thread function */ - SOKOL_ASSERT(thread && thread->valid); - SOKOL_ASSERT(outgoing && outgoing->buf); - SOKOL_ASSERT(0 != item); - pthread_mutex_lock(&thread->outgoing_mutex); - bool result = false; - if (!_sfetch_ring_full(outgoing)) { - _sfetch_ring_enqueue(outgoing, item); - } - pthread_mutex_unlock(&thread->outgoing_mutex); - return result; -} - -_SOKOL_PRIVATE void _sfetch_thread_dequeue_outgoing(_sfetch_thread_t* thread, _sfetch_ring_t* outgoing, _sfetch_ring_t* dst) { - /* called from user thread */ - SOKOL_ASSERT(thread && thread->valid); - SOKOL_ASSERT(outgoing && outgoing->buf); - SOKOL_ASSERT(dst && dst->buf); - pthread_mutex_lock(&thread->outgoing_mutex); - while (!_sfetch_ring_full(dst) && !_sfetch_ring_empty(outgoing)) { - _sfetch_ring_enqueue(dst, _sfetch_ring_dequeue(outgoing)); - } - pthread_mutex_unlock(&thread->outgoing_mutex); -} -#endif /* _SFETCH_PLATFORM_POSIX */ - -// ██ ██ ██ ███ ██ ██████ ██████ ██ ██ ███████ -// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ █ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ █ ██ ███████ -// ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ -// ███ ███ ██ ██ ████ ██████ ██████ ███ ███ ███████ -// -// >>windows -#if _SFETCH_PLATFORM_WINDOWS -_SOKOL_PRIVATE bool _sfetch_win32_utf8_to_wide(const char* src, wchar_t* dst, int dst_num_bytes) { - SOKOL_ASSERT(src && dst && (dst_num_bytes > 1)); - _sfetch_clear(dst, (size_t)dst_num_bytes); - const int dst_chars = dst_num_bytes / (int)sizeof(wchar_t); - const int dst_needed = MultiByteToWideChar(CP_UTF8, 0, src, -1, 0, 0); - if ((dst_needed > 0) && (dst_needed < dst_chars)) { - MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, dst_chars); - return true; - } - else { - /* input string doesn't fit into destination buffer */ - return false; - } -} - -_SOKOL_PRIVATE _sfetch_file_handle_t _sfetch_file_open(const _sfetch_path_t* path) { - wchar_t w_path[SFETCH_MAX_PATH]; - if (!_sfetch_win32_utf8_to_wide(path->buf, w_path, sizeof(w_path))) { - _SFETCH_ERROR(FILE_PATH_UTF8_DECODING_FAILED); - return 0; - } - _sfetch_file_handle_t h = CreateFileW( - w_path, /* lpFileName */ - GENERIC_READ, /* dwDesiredAccess */ - FILE_SHARE_READ, /* dwShareMode */ - NULL, /* lpSecurityAttributes */ - OPEN_EXISTING, /* dwCreationDisposition */ - FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, /* dwFlagsAndAttributes */ - NULL); /* hTemplateFile */ - return h; -} - -_SOKOL_PRIVATE void _sfetch_file_close(_sfetch_file_handle_t h) { - CloseHandle(h); -} - -_SOKOL_PRIVATE bool _sfetch_file_handle_valid(_sfetch_file_handle_t h) { - return h != _SFETCH_INVALID_FILE_HANDLE; -} - -_SOKOL_PRIVATE uint32_t _sfetch_file_size(_sfetch_file_handle_t h) { - return GetFileSize(h, NULL); -} - -_SOKOL_PRIVATE bool _sfetch_file_read(_sfetch_file_handle_t h, uint32_t offset, uint32_t num_bytes, void* ptr) { - LARGE_INTEGER offset_li; - offset_li.QuadPart = offset; - BOOL seek_res = SetFilePointerEx(h, offset_li, NULL, FILE_BEGIN); - if (seek_res) { - DWORD bytes_read = 0; - BOOL read_res = ReadFile(h, ptr, (DWORD)num_bytes, &bytes_read, NULL); - return read_res && (bytes_read == num_bytes); - } - else { - return false; - } -} - -_SOKOL_PRIVATE bool _sfetch_thread_init(_sfetch_thread_t* thread, _sfetch_thread_func_t thread_func, void* thread_arg) { - SOKOL_ASSERT(thread && !thread->valid && !thread->stop_requested); - - thread->incoming_event = CreateEventA(NULL, FALSE, FALSE, NULL); - SOKOL_ASSERT(NULL != thread->incoming_event); - InitializeCriticalSection(&thread->incoming_critsec); - InitializeCriticalSection(&thread->outgoing_critsec); - InitializeCriticalSection(&thread->running_critsec); - InitializeCriticalSection(&thread->stop_critsec); - - EnterCriticalSection(&thread->running_critsec); - const SIZE_T stack_size = 512 * 1024; - thread->thread = CreateThread(NULL, stack_size, thread_func, thread_arg, 0, NULL); - thread->valid = (NULL != thread->thread); - LeaveCriticalSection(&thread->running_critsec); - return thread->valid; -} - -_SOKOL_PRIVATE void _sfetch_thread_request_stop(_sfetch_thread_t* thread) { - EnterCriticalSection(&thread->stop_critsec); - thread->stop_requested = true; - LeaveCriticalSection(&thread->stop_critsec); -} - -_SOKOL_PRIVATE bool _sfetch_thread_stop_requested(_sfetch_thread_t* thread) { - EnterCriticalSection(&thread->stop_critsec); - bool stop_requested = thread->stop_requested; - LeaveCriticalSection(&thread->stop_critsec); - return stop_requested; -} - -_SOKOL_PRIVATE void _sfetch_thread_join(_sfetch_thread_t* thread) { - if (thread->valid) { - EnterCriticalSection(&thread->incoming_critsec); - _sfetch_thread_request_stop(thread); - BOOL set_event_res = SetEvent(thread->incoming_event); - _SOKOL_UNUSED(set_event_res); - SOKOL_ASSERT(set_event_res); - LeaveCriticalSection(&thread->incoming_critsec); - WaitForSingleObject(thread->thread, INFINITE); - CloseHandle(thread->thread); - thread->valid = false; - } - CloseHandle(thread->incoming_event); - DeleteCriticalSection(&thread->stop_critsec); - DeleteCriticalSection(&thread->running_critsec); - DeleteCriticalSection(&thread->outgoing_critsec); - DeleteCriticalSection(&thread->incoming_critsec); -} - -_SOKOL_PRIVATE void _sfetch_thread_entered(_sfetch_thread_t* thread) { - EnterCriticalSection(&thread->running_critsec); -} - -/* called by the thread-func right before it is left */ -_SOKOL_PRIVATE void _sfetch_thread_leaving(_sfetch_thread_t* thread) { - LeaveCriticalSection(&thread->running_critsec); -} - -_SOKOL_PRIVATE void _sfetch_thread_enqueue_incoming(_sfetch_thread_t* thread, _sfetch_ring_t* incoming, _sfetch_ring_t* src) { - /* called from user thread */ - SOKOL_ASSERT(thread && thread->valid); - SOKOL_ASSERT(incoming && incoming->buf); - SOKOL_ASSERT(src && src->buf); - if (!_sfetch_ring_empty(src)) { - EnterCriticalSection(&thread->incoming_critsec); - while (!_sfetch_ring_full(incoming) && !_sfetch_ring_empty(src)) { - _sfetch_ring_enqueue(incoming, _sfetch_ring_dequeue(src)); - } - LeaveCriticalSection(&thread->incoming_critsec); - BOOL set_event_res = SetEvent(thread->incoming_event); - _SOKOL_UNUSED(set_event_res); - SOKOL_ASSERT(set_event_res); - } -} - -_SOKOL_PRIVATE uint32_t _sfetch_thread_dequeue_incoming(_sfetch_thread_t* thread, _sfetch_ring_t* incoming) { - /* called from thread function */ - SOKOL_ASSERT(thread && thread->valid); - SOKOL_ASSERT(incoming && incoming->buf); - EnterCriticalSection(&thread->incoming_critsec); - while (_sfetch_ring_empty(incoming) && !thread->stop_requested) { - LeaveCriticalSection(&thread->incoming_critsec); - WaitForSingleObject(thread->incoming_event, INFINITE); - EnterCriticalSection(&thread->incoming_critsec); - } - uint32_t item = 0; - if (!thread->stop_requested) { - item = _sfetch_ring_dequeue(incoming); - } - LeaveCriticalSection(&thread->incoming_critsec); - return item; -} - -_SOKOL_PRIVATE bool _sfetch_thread_enqueue_outgoing(_sfetch_thread_t* thread, _sfetch_ring_t* outgoing, uint32_t item) { - /* called from thread function */ - SOKOL_ASSERT(thread && thread->valid); - SOKOL_ASSERT(outgoing && outgoing->buf); - EnterCriticalSection(&thread->outgoing_critsec); - bool result = false; - if (!_sfetch_ring_full(outgoing)) { - _sfetch_ring_enqueue(outgoing, item); - } - LeaveCriticalSection(&thread->outgoing_critsec); - return result; -} - -_SOKOL_PRIVATE void _sfetch_thread_dequeue_outgoing(_sfetch_thread_t* thread, _sfetch_ring_t* outgoing, _sfetch_ring_t* dst) { - /* called from user thread */ - SOKOL_ASSERT(thread && thread->valid); - SOKOL_ASSERT(outgoing && outgoing->buf); - SOKOL_ASSERT(dst && dst->buf); - EnterCriticalSection(&thread->outgoing_critsec); - while (!_sfetch_ring_full(dst) && !_sfetch_ring_empty(outgoing)) { - _sfetch_ring_enqueue(dst, _sfetch_ring_dequeue(outgoing)); - } - LeaveCriticalSection(&thread->outgoing_critsec); -} -#endif /* _SFETCH_PLATFORM_WINDOWS */ - -// ██████ ██ ██ █████ ███ ██ ███ ██ ███████ ██ ███████ -// ██ ██ ██ ██ ██ ████ ██ ████ ██ ██ ██ ██ -// ██ ███████ ███████ ██ ██ ██ ██ ██ ██ █████ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ ████ ██ ████ ███████ ███████ ███████ -// -// >>channels - -/* per-channel request handler for native platforms accessing the local filesystem */ -#if _SFETCH_HAS_THREADS -_SOKOL_PRIVATE void _sfetch_request_handler(_sfetch_t* ctx, uint32_t slot_id) { - _sfetch_state_t state; - _sfetch_path_t* path; - _sfetch_item_thread_t* thread; - sfetch_range_t* buffer; - uint32_t chunk_size; - { - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, slot_id); - if (!item) { - return; - } - state = item->state; - SOKOL_ASSERT((state == _SFETCH_STATE_FETCHING) || - (state == _SFETCH_STATE_PAUSED) || - (state == _SFETCH_STATE_FAILED)); - path = &item->path; - thread = &item->thread; - buffer = &item->buffer; - chunk_size = item->chunk_size; - } - if (thread->failed) { - return; - } - if (state == _SFETCH_STATE_FETCHING) { - if ((buffer->ptr == 0) || (buffer->size == 0)) { - thread->error_code = SFETCH_ERROR_NO_BUFFER; - thread->failed = true; - } - else { - /* open file if not happened yet */ - if (!_sfetch_file_handle_valid(thread->file_handle)) { - SOKOL_ASSERT(path->buf[0]); - SOKOL_ASSERT(thread->fetched_offset == 0); - SOKOL_ASSERT(thread->fetched_size == 0); - thread->file_handle = _sfetch_file_open(path); - if (_sfetch_file_handle_valid(thread->file_handle)) { - thread->content_size = _sfetch_file_size(thread->file_handle); - } - else { - thread->error_code = SFETCH_ERROR_FILE_NOT_FOUND; - thread->failed = true; - } - } - if (!thread->failed) { - uint32_t read_offset = 0; - uint32_t bytes_to_read = 0; - if (chunk_size == 0) { - /* load entire file */ - if (thread->content_size <= buffer->size) { - bytes_to_read = thread->content_size; - read_offset = 0; - } - else { - /* provided buffer to small to fit entire file */ - thread->error_code = SFETCH_ERROR_BUFFER_TOO_SMALL; - thread->failed = true; - } - } - else { - if (chunk_size <= buffer->size) { - bytes_to_read = chunk_size; - read_offset = thread->fetched_offset; - if ((read_offset + bytes_to_read) > thread->content_size) { - bytes_to_read = thread->content_size - read_offset; - } - } - else { - /* provided buffer to small to fit next chunk */ - thread->error_code = SFETCH_ERROR_BUFFER_TOO_SMALL; - thread->failed = true; - } - } - if (!thread->failed) { - if (_sfetch_file_read(thread->file_handle, read_offset, bytes_to_read, (void*)buffer->ptr)) { - thread->fetched_size = bytes_to_read; - thread->fetched_offset += bytes_to_read; - } - else { - thread->error_code = SFETCH_ERROR_UNEXPECTED_EOF; - thread->failed = true; - } - } - } - } - SOKOL_ASSERT(thread->fetched_offset <= thread->content_size); - if (thread->failed || (thread->fetched_offset == thread->content_size)) { - if (_sfetch_file_handle_valid(thread->file_handle)) { - _sfetch_file_close(thread->file_handle); - thread->file_handle = _SFETCH_INVALID_FILE_HANDLE; - } - thread->finished = true; - } - } - /* ignore items in PAUSED or FAILED state */ -} - -#if _SFETCH_PLATFORM_WINDOWS -_SOKOL_PRIVATE DWORD WINAPI _sfetch_channel_thread_func(LPVOID arg) { -#else -_SOKOL_PRIVATE void* _sfetch_channel_thread_func(void* arg) { -#endif - _sfetch_channel_t* chn = (_sfetch_channel_t*) arg; - _sfetch_thread_entered(&chn->thread); - while (!_sfetch_thread_stop_requested(&chn->thread)) { - /* block until work arrives */ - uint32_t slot_id = _sfetch_thread_dequeue_incoming(&chn->thread, &chn->thread_incoming); - /* slot_id will be invalid if the thread was woken up to join */ - if (!_sfetch_thread_stop_requested(&chn->thread)) { - SOKOL_ASSERT(0 != slot_id); - chn->request_handler(chn->ctx, slot_id); - SOKOL_ASSERT(!_sfetch_ring_full(&chn->thread_outgoing)); - _sfetch_thread_enqueue_outgoing(&chn->thread, &chn->thread_outgoing, slot_id); - } - } - _sfetch_thread_leaving(&chn->thread); - return 0; -} -#endif /* _SFETCH_HAS_THREADS */ - -#if _SFETCH_PLATFORM_EMSCRIPTEN -EM_JS(void, sfetch_js_send_head_request, (uint32_t slot_id, const char* path_cstr), { - const path_str = UTF8ToString(path_cstr); - const req = new XMLHttpRequest(); - req.open('HEAD', path_str); - req.onreadystatechange = function() { - if (req.readyState == XMLHttpRequest.DONE) { - if (req.status == 200) { - const content_length = req.getResponseHeader('Content-Length'); - __sfetch_emsc_head_response(slot_id, content_length); - } - else { - __sfetch_emsc_failed_http_status(slot_id, req.status); - } - } - }; - req.send(); -}); - -/* if bytes_to_read != 0, a range-request will be sent, otherwise a normal request */ -EM_JS(void, sfetch_js_send_get_request, (uint32_t slot_id, const char* path_cstr, uint32_t offset, uint32_t bytes_to_read, void* buf_ptr, uint32_t buf_size), { - const path_str = UTF8ToString(path_cstr); - const req = new XMLHttpRequest(); - req.open('GET', path_str); - req.responseType = 'arraybuffer'; - const need_range_request = (bytes_to_read > 0); - if (need_range_request) { - req.setRequestHeader('Range', 'bytes='+offset+'-'+(offset+bytes_to_read-1)); - } - req.onreadystatechange = function() { - if (req.readyState == XMLHttpRequest.DONE) { - if ((req.status == 206) || ((req.status == 200) && !need_range_request)) { - const u8_array = new Uint8Array(\x2F\x2A\x2A @type {!ArrayBuffer} \x2A\x2F (req.response)); - const content_fetched_size = u8_array.length; - if (content_fetched_size <= buf_size) { - HEAPU8.set(u8_array, buf_ptr); - __sfetch_emsc_get_response(slot_id, bytes_to_read, content_fetched_size); - } - else { - __sfetch_emsc_failed_buffer_too_small(slot_id); - } - } - else { - __sfetch_emsc_failed_http_status(slot_id, req.status); - } - } - }; - req.send(); -}); - -/*=== emscripten specific C helper functions =================================*/ -#ifdef __cplusplus -extern "C" { -#endif -void _sfetch_emsc_send_get_request(uint32_t slot_id, _sfetch_item_t* item) { - if ((item->buffer.ptr == 0) || (item->buffer.size == 0)) { - item->thread.error_code = SFETCH_ERROR_NO_BUFFER; - item->thread.failed = true; - } - else { - uint32_t offset = 0; - uint32_t bytes_to_read = 0; - if (item->chunk_size > 0) { - /* send HTTP range request */ - SOKOL_ASSERT(item->thread.content_size > 0); - SOKOL_ASSERT(item->thread.http_range_offset < item->thread.content_size); - bytes_to_read = item->thread.content_size - item->thread.http_range_offset; - if (bytes_to_read > item->chunk_size) { - bytes_to_read = item->chunk_size; - } - SOKOL_ASSERT(bytes_to_read > 0); - offset = item->thread.http_range_offset; - } - sfetch_js_send_get_request(slot_id, item->path.buf, offset, bytes_to_read, (void*)item->buffer.ptr, item->buffer.size); - } -} - -/* called by JS when an initial HEAD request finished successfully (only when streaming chunks) */ -EMSCRIPTEN_KEEPALIVE void _sfetch_emsc_head_response(uint32_t slot_id, uint32_t content_length) { - _sfetch_t* ctx = _sfetch_ctx(); - if (ctx && ctx->valid) { - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, slot_id); - if (item) { - SOKOL_ASSERT(item->buffer.ptr && (item->buffer.size > 0)); - item->thread.content_size = content_length; - _sfetch_emsc_send_get_request(slot_id, item); - } - } -} - -/* called by JS when a followup GET request finished successfully */ -EMSCRIPTEN_KEEPALIVE void _sfetch_emsc_get_response(uint32_t slot_id, uint32_t range_fetched_size, uint32_t content_fetched_size) { - _sfetch_t* ctx = _sfetch_ctx(); - if (ctx && ctx->valid) { - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, slot_id); - if (item) { - item->thread.fetched_size = content_fetched_size; - item->thread.fetched_offset += content_fetched_size; - item->thread.http_range_offset += range_fetched_size; - if (item->chunk_size == 0) { - item->thread.finished = true; - } - else if (item->thread.http_range_offset >= item->thread.content_size) { - item->thread.finished = true; - } - _sfetch_ring_enqueue(&ctx->chn[item->channel].user_outgoing, slot_id); - } - } -} - -/* called by JS when an error occurred */ -EMSCRIPTEN_KEEPALIVE void _sfetch_emsc_failed_http_status(uint32_t slot_id, uint32_t http_status) { - _sfetch_t* ctx = _sfetch_ctx(); - if (ctx && ctx->valid) { - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, slot_id); - if (item) { - if (http_status == 404) { - item->thread.error_code = SFETCH_ERROR_FILE_NOT_FOUND; - } - else { - item->thread.error_code = SFETCH_ERROR_INVALID_HTTP_STATUS; - } - item->thread.failed = true; - item->thread.finished = true; - _sfetch_ring_enqueue(&ctx->chn[item->channel].user_outgoing, slot_id); - } - } -} - -EMSCRIPTEN_KEEPALIVE void _sfetch_emsc_failed_buffer_too_small(uint32_t slot_id) { - _sfetch_t* ctx = _sfetch_ctx(); - if (ctx && ctx->valid) { - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, slot_id); - if (item) { - item->thread.error_code = SFETCH_ERROR_BUFFER_TOO_SMALL; - item->thread.failed = true; - item->thread.finished = true; - _sfetch_ring_enqueue(&ctx->chn[item->channel].user_outgoing, slot_id); - } - } -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -_SOKOL_PRIVATE void _sfetch_request_handler(_sfetch_t* ctx, uint32_t slot_id) { - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, slot_id); - if (!item) { - return; - } - if (item->state == _SFETCH_STATE_FETCHING) { - if ((item->chunk_size > 0) && (item->thread.content_size == 0)) { - /* if streaming download is requested, and the content-length isn't known - yet, need to send a HEAD request first - */ - sfetch_js_send_head_request(slot_id, item->path.buf); - } - else { - /* otherwise, this is either a request to load the entire file, or - to load the next streaming chunk - */ - _sfetch_emsc_send_get_request(slot_id, item); - } - } - else { - /* just move all other items (e.g. paused or cancelled) - into the outgoing queue, so they won't get lost - */ - _sfetch_ring_enqueue(&ctx->chn[item->channel].user_outgoing, slot_id); - } - if (item->thread.failed) { - item->thread.finished = true; - } -} -#endif /* _SFETCH_PLATFORM_EMSCRIPTEN */ - -_SOKOL_PRIVATE void _sfetch_channel_discard(_sfetch_channel_t* chn) { - SOKOL_ASSERT(chn); - #if _SFETCH_HAS_THREADS - if (chn->valid) { - _sfetch_thread_join(&chn->thread); - } - _sfetch_ring_discard(&chn->thread_incoming); - _sfetch_ring_discard(&chn->thread_outgoing); - #endif - _sfetch_ring_discard(&chn->free_lanes); - _sfetch_ring_discard(&chn->user_sent); - _sfetch_ring_discard(&chn->user_incoming); - _sfetch_ring_discard(&chn->user_outgoing); - _sfetch_ring_discard(&chn->free_lanes); - chn->valid = false; -} - -_SOKOL_PRIVATE bool _sfetch_channel_init(_sfetch_channel_t* chn, _sfetch_t* ctx, uint32_t num_items, uint32_t num_lanes, void (*request_handler)(_sfetch_t* ctx, uint32_t)) { - SOKOL_ASSERT(chn && (num_items > 0) && request_handler); - SOKOL_ASSERT(!chn->valid); - bool valid = true; - chn->request_handler = request_handler; - chn->ctx = ctx; - valid &= _sfetch_ring_init(&chn->free_lanes, num_lanes); - for (uint32_t lane = 0; lane < num_lanes; lane++) { - _sfetch_ring_enqueue(&chn->free_lanes, lane); - } - valid &= _sfetch_ring_init(&chn->user_sent, num_items); - valid &= _sfetch_ring_init(&chn->user_incoming, num_lanes); - valid &= _sfetch_ring_init(&chn->user_outgoing, num_lanes); - #if _SFETCH_HAS_THREADS - valid &= _sfetch_ring_init(&chn->thread_incoming, num_lanes); - valid &= _sfetch_ring_init(&chn->thread_outgoing, num_lanes); - #endif - if (valid) { - chn->valid = true; - #if _SFETCH_HAS_THREADS - _sfetch_thread_init(&chn->thread, _sfetch_channel_thread_func, chn); - #endif - return true; - } - else { - _sfetch_channel_discard(chn); - return false; - } -} - -/* put a request into the channels sent-queue, this is where all new requests - are stored until a lane becomes free. -*/ -_SOKOL_PRIVATE bool _sfetch_channel_send(_sfetch_channel_t* chn, uint32_t slot_id) { - SOKOL_ASSERT(chn && chn->valid); - if (!_sfetch_ring_full(&chn->user_sent)) { - _sfetch_ring_enqueue(&chn->user_sent, slot_id); - return true; - } - else { - _SFETCH_ERROR(SEND_QUEUE_FULL); - return false; - } -} - -_SOKOL_PRIVATE void _sfetch_invoke_response_callback(_sfetch_item_t* item) { - sfetch_response_t response; - _sfetch_clear(&response, sizeof(response)); - response.handle = item->handle; - response.dispatched = (item->state == _SFETCH_STATE_DISPATCHED); - response.fetched = (item->state == _SFETCH_STATE_FETCHED); - response.paused = (item->state == _SFETCH_STATE_PAUSED); - response.finished = item->user.finished; - response.failed = (item->state == _SFETCH_STATE_FAILED); - response.cancelled = item->user.cancel; - response.error_code = item->user.error_code; - response.channel = item->channel; - response.lane = item->lane; - response.path = item->path.buf; - response.user_data = item->user.user_data; - response.data_offset = item->user.fetched_offset - item->user.fetched_size; - response.data.ptr = item->buffer.ptr; - response.data.size = item->user.fetched_size; - response.buffer = item->buffer; - item->callback(&response); -} - -_SOKOL_PRIVATE void _sfetch_cancel_item(_sfetch_item_t* item) { - item->state = _SFETCH_STATE_FAILED; - item->user.finished = true; - item->user.error_code = SFETCH_ERROR_CANCELLED; -} - -/* per-frame channel stuff: move requests in and out of the IO threads, call response callbacks */ -_SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_t* pool) { - - /* move items from sent- to incoming-queue permitting free lanes */ - const uint32_t num_sent = _sfetch_ring_count(&chn->user_sent); - const uint32_t avail_lanes = _sfetch_ring_count(&chn->free_lanes); - const uint32_t num_move = (num_sent < avail_lanes) ? num_sent : avail_lanes; - for (uint32_t i = 0; i < num_move; i++) { - const uint32_t slot_id = _sfetch_ring_dequeue(&chn->user_sent); - _sfetch_item_t* item = _sfetch_pool_item_lookup(pool, slot_id); - SOKOL_ASSERT(item); - SOKOL_ASSERT(item->state == _SFETCH_STATE_ALLOCATED); - // if the item was cancelled early, kick it out immediately - if (item->user.cancel) { - _sfetch_cancel_item(item); - _sfetch_invoke_response_callback(item); - _sfetch_pool_item_free(pool, slot_id); - continue; - } - item->state = _SFETCH_STATE_DISPATCHED; - item->lane = _sfetch_ring_dequeue(&chn->free_lanes); - // if no buffer provided yet, invoke response callback to do so - if (0 == item->buffer.ptr) { - _sfetch_invoke_response_callback(item); - } - _sfetch_ring_enqueue(&chn->user_incoming, slot_id); - } - - /* prepare incoming items for being moved into the IO thread */ - const uint32_t num_incoming = _sfetch_ring_count(&chn->user_incoming); - for (uint32_t i = 0; i < num_incoming; i++) { - const uint32_t slot_id = _sfetch_ring_peek(&chn->user_incoming, i); - _sfetch_item_t* item = _sfetch_pool_item_lookup(pool, slot_id); - SOKOL_ASSERT(item); - SOKOL_ASSERT(item->state != _SFETCH_STATE_INITIAL); - SOKOL_ASSERT(item->state != _SFETCH_STATE_FETCHING); - /* transfer input params from user- to thread-data */ - if (item->user.pause) { - item->state = _SFETCH_STATE_PAUSED; - item->user.pause = false; - } - if (item->user.cont) { - if (item->state == _SFETCH_STATE_PAUSED) { - item->state = _SFETCH_STATE_FETCHED; - } - item->user.cont = false; - } - if (item->user.cancel) { - _sfetch_cancel_item(item); - } - switch (item->state) { - case _SFETCH_STATE_DISPATCHED: - case _SFETCH_STATE_FETCHED: - item->state = _SFETCH_STATE_FETCHING; - break; - default: break; - } - } - - #if _SFETCH_HAS_THREADS - /* move new items into the IO threads and processed items out of IO threads */ - _sfetch_thread_enqueue_incoming(&chn->thread, &chn->thread_incoming, &chn->user_incoming); - _sfetch_thread_dequeue_outgoing(&chn->thread, &chn->thread_outgoing, &chn->user_outgoing); - #else - /* without threading just directly dequeue items from the user_incoming queue and - call the request handler, the user_outgoing queue will be filled as the - asynchronous HTTP requests sent by the request handler are completed - */ - while (!_sfetch_ring_empty(&chn->user_incoming)) { - uint32_t slot_id = _sfetch_ring_dequeue(&chn->user_incoming); - _sfetch_request_handler(chn->ctx, slot_id); - } - #endif - - /* drain the outgoing queue, prepare items for invoking the response - callback, and finally call the response callback, free finished items - */ - while (!_sfetch_ring_empty(&chn->user_outgoing)) { - const uint32_t slot_id = _sfetch_ring_dequeue(&chn->user_outgoing); - SOKOL_ASSERT(slot_id); - _sfetch_item_t* item = _sfetch_pool_item_lookup(pool, slot_id); - SOKOL_ASSERT(item && item->callback); - SOKOL_ASSERT(item->state != _SFETCH_STATE_INITIAL); - SOKOL_ASSERT(item->state != _SFETCH_STATE_ALLOCATED); - SOKOL_ASSERT(item->state != _SFETCH_STATE_DISPATCHED); - SOKOL_ASSERT(item->state != _SFETCH_STATE_FETCHED); - /* transfer output params from thread- to user-data */ - item->user.fetched_offset = item->thread.fetched_offset; - item->user.fetched_size = item->thread.fetched_size; - if (item->user.cancel) { - _sfetch_cancel_item(item); - } - else { - item->user.error_code = item->thread.error_code; - } - if (item->thread.finished) { - item->user.finished = true; - } - /* state transition */ - if (item->thread.failed) { - item->state = _SFETCH_STATE_FAILED; - } - else if (item->state == _SFETCH_STATE_FETCHING) { - item->state = _SFETCH_STATE_FETCHED; - } - _sfetch_invoke_response_callback(item); - - /* when the request is finished, free the lane for another request, - otherwise feed it back into the incoming queue - */ - if (item->user.finished) { - _sfetch_ring_enqueue(&chn->free_lanes, item->lane); - _sfetch_pool_item_free(pool, slot_id); - } - else { - _sfetch_ring_enqueue(&chn->user_incoming, slot_id); - } - } -} - -_SOKOL_PRIVATE bool _sfetch_validate_request(_sfetch_t* ctx, const sfetch_request_t* req) { - if (req->channel >= ctx->desc.num_channels) { - _SFETCH_ERROR(REQUEST_CHANNEL_INDEX_TOO_BIG); - return false; - } - if (!req->path) { - _SFETCH_ERROR(REQUEST_PATH_IS_NULL); - return false; - } - if (strlen(req->path) >= (SFETCH_MAX_PATH-1)) { - _SFETCH_ERROR(REQUEST_PATH_TOO_LONG); - return false; - } - if (!req->callback) { - _SFETCH_ERROR(REQUEST_CALLBACK_MISSING); - return false; - } - if (req->chunk_size > req->buffer.size) { - _SFETCH_ERROR(REQUEST_CHUNK_SIZE_GREATER_BUFFER_SIZE); - return false; - } - if (req->user_data.ptr && (req->user_data.size == 0)) { - _SFETCH_ERROR(REQUEST_USERDATA_PTR_IS_SET_BUT_USERDATA_SIZE_IS_NULL); - return false; - } - if (!req->user_data.ptr && (req->user_data.size > 0)) { - _SFETCH_ERROR(REQUEST_USERDATA_PTR_IS_NULL_BUT_USERDATA_SIZE_IS_NOT); - return false; - } - if (req->user_data.size > SFETCH_MAX_USERDATA_UINT64 * sizeof(uint64_t)) { - _SFETCH_ERROR(REQUEST_USERDATA_SIZE_TOO_BIG); - return false; - } - return true; -} - -_SOKOL_PRIVATE sfetch_desc_t _sfetch_desc_defaults(const sfetch_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sfetch_desc_t res = *desc; - res.max_requests = _sfetch_def(desc->max_requests, 128); - res.num_channels = _sfetch_def(desc->num_channels, 1); - res.num_lanes = _sfetch_def(desc->num_lanes, 1); - return res; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void sfetch_setup(const sfetch_desc_t* desc_) { - SOKOL_ASSERT(desc_); - SOKOL_ASSERT(0 == _sfetch); - - sfetch_desc_t desc = _sfetch_desc_defaults(desc_); - _sfetch = (_sfetch_t*) _sfetch_malloc_with_allocator(&desc.allocator, sizeof(_sfetch_t)); - SOKOL_ASSERT(_sfetch); - _sfetch_t* ctx = _sfetch_ctx(); - _sfetch_clear(ctx, sizeof(_sfetch_t)); - ctx->desc = desc; - ctx->setup = true; - ctx->valid = true; - - /* replace zero-init items with default values */ - if (ctx->desc.num_channels > SFETCH_MAX_CHANNELS) { - ctx->desc.num_channels = SFETCH_MAX_CHANNELS; - _SFETCH_WARN(CLAMPING_NUM_CHANNELS_TO_MAX_CHANNELS); - } - - /* setup the global request item pool */ - ctx->valid &= _sfetch_pool_init(&ctx->pool, ctx->desc.max_requests); - - /* setup IO channels (one thread per channel) */ - for (uint32_t i = 0; i < ctx->desc.num_channels; i++) { - ctx->valid &= _sfetch_channel_init(&ctx->chn[i], ctx, ctx->desc.max_requests, ctx->desc.num_lanes, _sfetch_request_handler); - } -} - -SOKOL_API_IMPL void sfetch_shutdown(void) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->setup); - ctx->valid = false; - /* IO threads must be shutdown first */ - for (uint32_t i = 0; i < ctx->desc.num_channels; i++) { - if (ctx->chn[i].valid) { - _sfetch_channel_discard(&ctx->chn[i]); - } - } - _sfetch_pool_discard(&ctx->pool); - ctx->setup = false; - _sfetch_free(ctx); - _sfetch = 0; -} - -SOKOL_API_IMPL bool sfetch_valid(void) { - _sfetch_t* ctx = _sfetch_ctx(); - return ctx && ctx->valid; -} - -SOKOL_API_IMPL sfetch_desc_t sfetch_desc(void) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->valid); - return ctx->desc; -} - -SOKOL_API_IMPL int sfetch_max_userdata_bytes(void) { - return SFETCH_MAX_USERDATA_UINT64 * 8; -} - -SOKOL_API_IMPL int sfetch_max_path(void) { - return SFETCH_MAX_PATH; -} - -SOKOL_API_IMPL bool sfetch_handle_valid(sfetch_handle_t h) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->valid); - /* shortcut invalid handle */ - if (h.id == 0) { - return false; - } - return 0 != _sfetch_pool_item_lookup(&ctx->pool, h.id); -} - -SOKOL_API_IMPL sfetch_handle_t sfetch_send(const sfetch_request_t* request) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->setup); - - const sfetch_handle_t invalid_handle = _sfetch_make_handle(0); - if (!ctx->valid) { - return invalid_handle; - } - if (!_sfetch_validate_request(ctx, request)) { - return invalid_handle; - } - SOKOL_ASSERT(request->channel < ctx->desc.num_channels); - - uint32_t slot_id = _sfetch_pool_item_alloc(&ctx->pool, request); - if (0 == slot_id) { - _SFETCH_WARN(REQUEST_POOL_EXHAUSTED); - return invalid_handle; - } - if (!_sfetch_channel_send(&ctx->chn[request->channel], slot_id)) { - /* send failed because the channels sent-queue overflowed */ - _sfetch_pool_item_free(&ctx->pool, slot_id); - return invalid_handle; - } - return _sfetch_make_handle(slot_id); -} - -SOKOL_API_IMPL void sfetch_dowork(void) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->setup); - if (!ctx->valid) { - return; - } - /* we're pumping each channel 2x so that unfinished request items coming out the - IO threads can be moved back into the IO-thread immediately without - having to wait a frame - */ - ctx->in_callback = true; - for (int pass = 0; pass < 2; pass++) { - for (uint32_t chn_index = 0; chn_index < ctx->desc.num_channels; chn_index++) { - _sfetch_channel_dowork(&ctx->chn[chn_index], &ctx->pool); - } - } - ctx->in_callback = false; -} - -SOKOL_API_IMPL void sfetch_bind_buffer(sfetch_handle_t h, sfetch_range_t buffer) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->valid); - SOKOL_ASSERT(ctx->in_callback); - SOKOL_ASSERT(buffer.ptr && (buffer.size > 0)); - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, h.id); - if (item) { - SOKOL_ASSERT((0 == item->buffer.ptr) && (0 == item->buffer.size)); - item->buffer = buffer; - } -} - -SOKOL_API_IMPL void* sfetch_unbind_buffer(sfetch_handle_t h) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->valid); - SOKOL_ASSERT(ctx->in_callback); - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, h.id); - if (item) { - void* prev_buf_ptr = (void*)item->buffer.ptr; - item->buffer.ptr = 0; - item->buffer.size = 0; - return prev_buf_ptr; - } - else { - return 0; - } -} - -SOKOL_API_IMPL void sfetch_pause(sfetch_handle_t h) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->valid); - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, h.id); - if (item) { - item->user.pause = true; - item->user.cont = false; - } -} - -SOKOL_API_IMPL void sfetch_continue(sfetch_handle_t h) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->valid); - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, h.id); - if (item) { - item->user.cont = true; - item->user.pause = false; - } -} - -SOKOL_API_IMPL void sfetch_cancel(sfetch_handle_t h) { - _sfetch_t* ctx = _sfetch_ctx(); - SOKOL_ASSERT(ctx && ctx->valid); - _sfetch_item_t* item = _sfetch_pool_item_lookup(&ctx->pool, h.id); - if (item) { - item->user.cont = false; - item->user.pause = false; - item->user.cancel = true; - } -} - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#endif /* SOKOL_FETCH_IMPL */ diff --git a/source/thirdparty/sokol/sokol_gfx.h b/source/thirdparty/sokol/sokol_gfx.h deleted file mode 100644 index c1b1d019..00000000 --- a/source/thirdparty/sokol/sokol_gfx.h +++ /dev/null @@ -1,19540 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_GFX_IMPL) -#define SOKOL_GFX_IMPL -#endif -#ifndef SOKOL_GFX_INCLUDED -/* - sokol_gfx.h -- simple 3D API wrapper - - Project URL: https://github.com/floooh/sokol - - Example code: https://github.com/floooh/sokol-samples - - Do this: - #define SOKOL_IMPL or - #define SOKOL_GFX_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - In the same place define one of the following to select the rendering - backend: - #define SOKOL_GLCORE - #define SOKOL_GLES3 - #define SOKOL_D3D11 - #define SOKOL_METAL - #define SOKOL_WGPU - #define SOKOL_DUMMY_BACKEND - - I.e. for the desktop GL it should look like this: - - #include ... - #include ... - #define SOKOL_IMPL - #define SOKOL_GLCORE - #include "sokol_gfx.h" - - The dummy backend replaces the platform-specific backend code with empty - stub functions. This is useful for writing tests that need to run on the - command line. - - Optionally provide the following defines with your own implementations: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - SOKOL_GFX_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_GFX_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_TRACE_HOOKS - enable trace hook callbacks (search below for TRACE HOOKS) - SOKOL_EXTERNAL_GL_LOADER - indicates that you're using your own GL loader, in this case - sokol_gfx.h will not include any platform GL headers and disable - the integrated Win32 GL loader - - If sokol_gfx.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_GFX_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - If you want to compile without deprecated structs and functions, - define: - - SOKOL_NO_DEPRECATED - - Optionally define the following to force debug checks and validations - even in release mode: - - SOKOL_DEBUG - by default this is defined if _DEBUG is defined - - sokol_gfx DOES NOT: - =================== - - create a window, swapchain or the 3D-API context/device, you must do this - before sokol_gfx is initialized, and pass any required information - (like 3D device pointers) to the sokol_gfx initialization call - - - present the rendered frame, how this is done exactly usually depends - on how the window and 3D-API context/device was created - - - provide a unified shader language, instead 3D-API-specific shader - source-code or shader-bytecode must be provided (for the "official" - offline shader cross-compiler, see here: - https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md) - - - STEP BY STEP - ============ - --- to initialize sokol_gfx, after creating a window and a 3D-API - context/device, call: - - sg_setup(const sg_desc*) - - Depending on the selected 3D backend, sokol-gfx requires some - information, like a device pointer, default swapchain pixel formats - and so on. If you are using sokol_app.h for the window system - glue, you can use a helper function provided in the sokol_glue.h - header: - - #include "sokol_gfx.h" - #include "sokol_app.h" - #include "sokol_glue.h" - //... - sg_setup(&(sg_desc){ - .environment = sglue_environment(), - }); - - To get any logging output for errors and from the validation layer, you - need to provide a logging callback. Easiest way is through sokol_log.h: - - #include "sokol_log.h" - //... - sg_setup(&(sg_desc){ - //... - .logger.func = slog_func, - }); - - --- create resource objects (at least buffers, shaders and pipelines, - and optionally images, samplers and render-pass-attachments): - - sg_buffer sg_make_buffer(const sg_buffer_desc*) - sg_image sg_make_image(const sg_image_desc*) - sg_sampler sg_make_sampler(const sg_sampler_desc*) - sg_shader sg_make_shader(const sg_shader_desc*) - sg_pipeline sg_make_pipeline(const sg_pipeline_desc*) - sg_attachments sg_make_attachments(const sg_attachments_desc*) - - --- start a render pass: - - sg_begin_pass(const sg_pass* pass); - - Typically, passes render into an externally provided swapchain which - presents the rendering result on the display. Such a 'swapchain pass' - is started like this: - - sg_begin_pass(&(sg_pass){ .action = { ... }, .swapchain = sglue_swapchain() }) - - ...where .action is an sg_pass_action struct containing actions to be performed - at the start and end of a render pass (such as clearing the render surfaces to - a specific color), and .swapchain is an sg_swapchain - struct all the required information to render into the swapchain's surfaces. - - To start an 'offscreen pass' into sokol-gfx image objects, an sg_attachment - object handle is required instead of an sg_swapchain struct. An offscreen - pass is started like this (assuming attachments is an sg_attachments handle): - - sg_begin_pass(&(sg_pass){ .action = { ... }, .attachments = attachments }); - - --- set the render pipeline state for the next draw call with: - - sg_apply_pipeline(sg_pipeline pip) - - --- fill an sg_bindings struct with the resource bindings for the next - draw call (0..N vertex buffers, 0 or 1 index buffer, 0..N image-objects, - samplers and storage-buffers), and call: - - sg_apply_bindings(const sg_bindings* bindings) - - to update the resource bindings - - --- optionally update shader uniform data with: - - sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data) - - Read the section 'UNIFORM DATA LAYOUT' to learn about the expected memory layout - of the uniform data passed into sg_apply_uniforms(). - - --- kick off a draw call with: - - sg_draw(int base_element, int num_elements, int num_instances) - - The sg_draw() function unifies all the different ways to render primitives - in a single call (indexed vs non-indexed rendering, and instanced vs non-instanced - rendering). In case of indexed rendering, base_element and num_element specify - indices in the currently bound index buffer. In case of non-indexed rendering - base_element and num_elements specify vertices in the currently bound - vertex-buffer(s). To perform instanced rendering, the rendering pipeline - must be setup for instancing (see sg_pipeline_desc below), a separate vertex buffer - containing per-instance data must be bound, and the num_instances parameter - must be > 1. - - --- finish the current rendering pass with: - - sg_end_pass() - - --- when done with the current frame, call - - sg_commit() - - --- at the end of your program, shutdown sokol_gfx with: - - sg_shutdown() - - --- if you need to destroy resources before sg_shutdown(), call: - - sg_destroy_buffer(sg_buffer buf) - sg_destroy_image(sg_image img) - sg_destroy_sampler(sg_sampler smp) - sg_destroy_shader(sg_shader shd) - sg_destroy_pipeline(sg_pipeline pip) - sg_destroy_attachments(sg_attachments atts) - - --- to set a new viewport rectangle, call - - sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left) - - ...or if you want to specify the viewport rectangle with float values: - - sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left) - - --- to set a new scissor rect, call: - - sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left) - - ...or with float values: - - sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left) - - Both sg_apply_viewport() and sg_apply_scissor_rect() must be called - inside a rendering pass - - Note that sg_begin_default_pass() and sg_begin_pass() will reset both the - viewport and scissor rectangles to cover the entire framebuffer. - - --- to update (overwrite) the content of buffer and image resources, call: - - sg_update_buffer(sg_buffer buf, const sg_range* data) - sg_update_image(sg_image img, const sg_image_data* data) - - Buffers and images to be updated must have been created with - SG_USAGE_DYNAMIC or SG_USAGE_STREAM - - Only one update per frame is allowed for buffer and image resources when - using the sg_update_*() functions. The rationale is to have a simple - countermeasure to avoid the CPU scribbling over data the GPU is currently - using, or the CPU having to wait for the GPU - - Buffer and image updates can be partial, as long as a rendering - operation only references the valid (updated) data in the - buffer or image. - - --- to append a chunk of data to a buffer resource, call: - - int sg_append_buffer(sg_buffer buf, const sg_range* data) - - The difference to sg_update_buffer() is that sg_append_buffer() - can be called multiple times per frame to append new data to the - buffer piece by piece, optionally interleaved with draw calls referencing - the previously written data. - - sg_append_buffer() returns a byte offset to the start of the - written data, this offset can be assigned to - sg_bindings.vertex_buffer_offsets[n] or - sg_bindings.index_buffer_offset - - Code example: - - for (...) { - const void* data = ...; - const int num_bytes = ...; - int offset = sg_append_buffer(buf, &(sg_range) { .ptr=data, .size=num_bytes }); - bindings.vertex_buffer_offsets[0] = offset; - sg_apply_pipeline(pip); - sg_apply_bindings(&bindings); - sg_apply_uniforms(...); - sg_draw(...); - } - - A buffer to be used with sg_append_buffer() must have been created - with SG_USAGE_DYNAMIC or SG_USAGE_STREAM. - - If the application appends more data to the buffer then fits into - the buffer, the buffer will go into the "overflow" state for the - rest of the frame. - - Any draw calls attempting to render an overflown buffer will be - silently dropped (in debug mode this will also result in a - validation error). - - You can also check manually if a buffer is in overflow-state by calling - - bool sg_query_buffer_overflow(sg_buffer buf) - - You can manually check to see if an overflow would occur before adding - any data to a buffer by calling - - bool sg_query_buffer_will_overflow(sg_buffer buf, size_t size) - - NOTE: Due to restrictions in underlying 3D-APIs, appended chunks of - data will be 4-byte aligned in the destination buffer. This means - that there will be gaps in index buffers containing 16-bit indices - when the number of indices in a call to sg_append_buffer() is - odd. This isn't a problem when each call to sg_append_buffer() - is associated with one draw call, but will be problematic when - a single indexed draw call spans several appended chunks of indices. - - --- to check at runtime for optional features, limits and pixelformat support, - call: - - sg_features sg_query_features() - sg_limits sg_query_limits() - sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt) - - --- if you need to call into the underlying 3D-API directly, you must call: - - sg_reset_state_cache() - - ...before calling sokol_gfx functions again - - --- you can inspect the original sg_desc structure handed to sg_setup() - by calling sg_query_desc(). This will return an sg_desc struct with - the default values patched in instead of any zero-initialized values - - --- you can get a desc struct matching the creation attributes of a - specific resource object via: - - sg_buffer_desc sg_query_buffer_desc(sg_buffer buf) - sg_image_desc sg_query_image_desc(sg_image img) - sg_sampler_desc sg_query_sampler_desc(sg_sampler smp) - sg_shader_desc sq_query_shader_desc(sg_shader shd) - sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip) - sg_attachments_desc sg_query_attachments_desc(sg_attachments atts) - - ...but NOTE that the returned desc structs may be incomplete, only - creation attributes that are kept around internally after resource - creation will be filled in, and in some cases (like shaders) that's - very little. Any missing attributes will be set to zero. The returned - desc structs might still be useful as partial blueprint for creating - similar resources if filled up with the missing attributes. - - Calling the query-desc functions on an invalid resource will return - completely zeroed structs (it makes sense to check the resource state - with sg_query_*_state() first) - - --- you can query the default resource creation parameters through the functions - - sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc) - sg_image_desc sg_query_image_defaults(const sg_image_desc* desc) - sg_sampler_desc sg_query_sampler_defaults(const sg_sampler_desc* desc) - sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc) - sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc) - sg_attachments_desc sg_query_attachments_defaults(const sg_attachments_desc* desc) - - These functions take a pointer to a desc structure which may contain - zero-initialized items for default values. These zero-init values - will be replaced with their concrete values in the returned desc - struct. - - --- you can inspect various internal resource runtime values via: - - sg_buffer_info sg_query_buffer_info(sg_buffer buf) - sg_image_info sg_query_image_info(sg_image img) - sg_sampler_info sg_query_sampler_info(sg_sampler smp) - sg_shader_info sg_query_shader_info(sg_shader shd) - sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip) - sg_attachments_info sg_query_attachments_info(sg_attachments atts) - - ...please note that the returned info-structs are tied quite closely - to sokol_gfx.h internals, and may change more often than other - public API functions and structs. - - --- you can query frame stats and control stats collection via: - - sg_query_frame_stats() - sg_enable_frame_stats() - sg_disable_frame_stats() - sg_frame_stats_enabled() - - --- you can ask at runtime what backend sokol_gfx.h has been compiled for: - - sg_backend sg_query_backend(void) - - --- call the following helper functions to compute the number of - bytes in a texture row or surface for a specific pixel format. - These functions might be helpful when preparing image data for consumption - by sg_make_image() or sg_update_image(): - - int sg_query_row_pitch(sg_pixel_format fmt, int width, int int row_align_bytes); - int sg_query_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align_bytes); - - Width and height are generally in number pixels, but note that 'row' has different meaning - for uncompressed vs compressed pixel formats: for uncompressed formats, a row is identical - with a single line if pixels, while in compressed formats, one row is a line of *compression blocks*. - - This is why calling sg_query_surface_pitch() for a compressed pixel format and height - N, N+1, N+2, ... may return the same result. - - The row_align_bytes parammeter is for added flexibility. For image data that goes into - the sg_make_image() or sg_update_image() this should generally be 1, because these - functions take tightly packed image data as input no matter what alignment restrictions - exist in the backend 3D APIs. - - ON INITIALIZATION: - ================== - When calling sg_setup(), a pointer to an sg_desc struct must be provided - which contains initialization options. These options provide two types - of information to sokol-gfx: - - (1) upper bounds and limits needed to allocate various internal - data structures: - - the max number of resources of each type that can - be alive at the same time, this is used for allocating - internal pools - - the max overall size of uniform data that can be - updated per frame, including a worst-case alignment - per uniform update (this worst-case alignment is 256 bytes) - - the max size of all dynamic resource updates (sg_update_buffer, - sg_append_buffer and sg_update_image) per frame - Not all of those limit values are used by all backends, but it is - good practice to provide them none-the-less. - - (2) 3D backend "environment information" in a nested sg_environment struct: - - pointers to backend-specific context- or device-objects (for instance - the D3D11, WebGPU or Metal device objects) - - defaults for external swapchain pixel formats and sample counts, - these will be used as default values in image and pipeline objects, - and the sg_swapchain struct passed into sg_begin_pass() - Usually you provide a complete sg_environment struct through - a helper function, as an example look at the sglue_environment() - function in the sokol_glue.h header. - - See the documentation block of the sg_desc struct below for more information. - - - ON RENDER PASSES - ================ - Relevant samples: - - https://floooh.github.io/sokol-html5/offscreen-sapp.html - - https://floooh.github.io/sokol-html5/offscreen-msaa-sapp.html - - https://floooh.github.io/sokol-html5/mrt-sapp.html - - https://floooh.github.io/sokol-html5/mrt-pixelformats-sapp.html - - A render pass groups rendering commands into a set of render target images - (called 'pass attachments'). Render target images can be used in subsequent - passes as textures (it is invalid to use the same image both as render target - and as texture in the same pass). - - The following sokol-gfx functions must only be called inside a render pass: - - sg_apply_viewport(f) - sg_apply_scissor_rect(f) - sg_apply_pipeline - sg_apply_bindings - sg_apply_uniforms - sg_draw - - A frame must have at least one 'swapchain render pass' which renders into an - externally provided swapchain provided as an sg_swapchain struct to the - sg_begin_pass() function. The sg_swapchain struct must contain the - following information: - - - the color pixel-format of the swapchain's render surface - - an optional depth/stencil pixel format if the swapchain - has a depth/stencil buffer - - an optional sample-count for MSAA rendering - - NOTE: the above three values can be zero-initialized, in that - case the defaults from the sg_environment struct will be used that - had been passed to the sg_setup() function. - - a number of backend specific objects: - - GL/GLES3: just a GL framebuffer handle - - D3D11: - - an ID3D11RenderTargetView for the rendering surface - - if MSAA is used, an ID3D11RenderTargetView as - MSAA resolve-target - - an optional ID3D11DepthStencilView for the - depth/stencil buffer - - WebGPU - - a WGPUTextureView object for the rendering surface - - if MSAA is used, a WGPUTextureView object as MSAA resolve target - - an optional WGPUTextureView for the - - Metal (NOTE that the roles of provided surfaces is slightly - different in Metal than in D3D11 or WebGPU, notably, the - CAMetalDrawable is either rendered to directly, or serves - as MSAA resolve target): - - a CAMetalDrawable object which is either rendered - into directly, or in case of MSAA rendering, serves - as MSAA-resolve-target - - if MSAA is used, an multisampled MTLTexture where - rendering goes into - - an optional MTLTexture for the depth/stencil buffer - - It's recommended that you create a helper function which returns an - initialized sg_swapchain struct by value. This can then be directly plugged - into the sg_begin_pass function like this: - - sg_begin_pass(&(sg_pass){ .swapchain = sglue_swapchain() }); - - As an example for such a helper function check out the function sglue_swapchain() - in the sokol_glue.h header. - - For offscreen render passes, the render target images used in a render pass - are baked into an immutable sg_attachments object. - - For a simple offscreen scenario with one color-, one depth-stencil-render - target and without multisampling, creating an attachment object looks like this: - - First create two render target images, one with a color pixel format, - and one with the depth- or depth-stencil pixel format. Both images - must have the same dimensions: - - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 256, - .height = 256, - .pixel_format = SG_PIXELFORMAT_RGBA8, - .sample_count = 1, - }); - const sg_image depth_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 256, - .height = 256, - .pixel_format = SG_PIXELFORMAT_DEPTH, - .sample_count = 1, - }); - - NOTE: when creating render target images, have in mind that some default values - are aligned with the default environment attributes in the sg_environment struct - that was passed into the sg_setup() call: - - - the default value for sg_image_desc.pixel_format is taken from - sg_environment.defaults.color_format - - the default value for sg_image_desc.sample_count is taken from - sg_environment.defaults.sample_count - - the default value for sg_image_desc.num_mipmaps is always 1 - - Next create an attachments object: - - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0].image = color_img, - .depth_stencil.image = depth_img, - }); - - This attachments object is then passed into the sg_begin_pass() function - in place of the swapchain struct: - - sg_begin_pass(&(sg_pass){ .attachments = atts }); - - Swapchain and offscreen passes form dependency trees each with a swapchain - pass at the root, offscreen passes as nodes, and render target images as - dependencies between passes. - - sg_pass_action structs are used to define actions that should happen at the - start and end of rendering passes (such as clearing pass attachments to a - specific color or depth-value, or performing an MSAA resolve operation at - the end of a pass). - - A typical sg_pass_action object which clears the color attachment to black - might look like this: - - const sg_pass_action = { - .colors[0] = { - .load_action = SG_LOADACTION_CLEAR, - .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f } - } - }; - - This omits the defaults for the color attachment store action, and - the depth-stencil-attachments actions. The same pass action with the - defaults explicitly filled in would look like this: - - const sg_pass_action pass_action = { - .colors[0] = { - .load_action = SG_LOADACTION_CLEAR, - .store_action = SG_STOREACTION_STORE, - .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f } - }, - .depth = = { - .load_action = SG_LOADACTION_CLEAR, - .store_action = SG_STOREACTION_DONTCARE, - .clear_value = 1.0f, - }, - .stencil = { - .load_action = SG_LOADACTION_CLEAR, - .store_action = SG_STOREACTION_DONTCARE, - .clear_value = 0 - } - }; - - With the sg_pass object and sg_pass_action struct in place everything - is ready now for the actual render pass: - - Using such this prepared sg_pass_action in a swapchain pass looks like - this: - - sg_begin_pass(&(sg_pass){ - .action = pass_action, - .swapchain = sglue_swapchain() - }); - ... - sg_end_pass(); - - ...of alternatively in one offscreen pass: - - sg_begin_pass(&(sg_pass){ - .action = pass_action, - .attachments = attachments, - }); - ... - sg_end_pass(); - - Offscreen rendering can also go into a mipmap, or a slice/face of - a cube-, array- or 3d-image (which some restrictions, for instance - it's not possible to create a 3D image with a depth/stencil pixel format, - these exceptions are generally caught by the sokol-gfx validation layer). - - The mipmap/slice selection happens at attachments creation time, for instance - to render into mipmap 2 of slice 3 of an array texture: - - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0] = { - .image = color_img, - .mip_level = 2, - .slice = 3, - }, - .depth_stencil.image = depth_img, - }); - - If MSAA offscreen rendering is desired, the multi-sample rendering result - must be 'resolved' into a separate 'resolve image', before that image can - be used as texture. - - NOTE: currently multisample-images cannot be bound as textures. - - Creating a simple attachments object for multisampled rendering requires - 3 attachment images: the color attachment image which has a sample - count > 1, a resolve attachment image of the same size and pixel format - but a sample count == 1, and a depth/stencil attachment image with - the same size and sample count as the color attachment image: - - const sg_image color_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 256, - .height = 256, - .pixel_format = SG_PIXELFORMAT_RGBA8, - .sample_count = 4, - }); - const sg_image resolve_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 256, - .height = 256, - .pixel_format = SG_PIXELFORMAT_RGBA8, - .sample_count = 1, - }); - const sg_image depth_img = sg_make_image(&(sg_image_desc){ - .render_target = true, - .width = 256, - .height = 256, - .pixel_format = SG_PIXELFORMAT_DEPTH, - .sample_count = 4, - }); - - ...create the attachments object: - - const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ - .colors[0].image = color_img, - .resolves[0].image = resolve_img, - .depth_stencil.image = depth_img, - }); - - If an attachments object defines a resolve image in a specific resolve attachment slot, - an 'msaa resolve operation' will happen in sg_end_pass(). - - In this scenario, the content of the MSAA color attachment doesn't need to be - preserved (since it's only needed inside sg_end_pass for the msaa-resolve), so - the .store_action should be set to "don't care": - - const sg_pass_action = { - .colors[0] = { - .load_action = SG_LOADACTION_CLEAR, - .store_action = SG_STOREACTION_DONTCARE, - .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f } - } - }; - - The actual render pass looks as usual: - - sg_begin_pass(&(sg_pass){ .action = pass_action, .attachments = atts }); - ... - sg_end_pass(); - - ...after sg_end_pass() the only difference to the non-msaa scenario is that the - rendering result which is going to be used as texture in a followup pass is - in 'resolve_img', not in 'color_img' (in fact, trying to bind color_img as a - texture would result in a validation error). - - - ON SHADER CREATION - ================== - sokol-gfx doesn't come with an integrated shader cross-compiler, instead - backend-specific shader sources or binary blobs need to be provided when - creating a shader object, along with information about the shader resource - binding interface needed in the sokol-gfx validation layer and to properly - bind shader resources on the CPU-side to be consumable by the GPU-side. - - The easiest way to provide all this shader creation data is to use the - sokol-shdc shader compiler tool to compile shaders from a common - GLSL syntax into backend-specific sources or binary blobs, along with - shader interface information and uniform blocks mapped to C structs. - - To create a shader using a C header which has been code-generated by sokol-shdc: - - // include the C header code-generated by sokol-shdc: - #include "myshader.glsl.h" - ... - - // create shader using a code-generated helper function from the C header: - sg_shader shd = sg_make_shader(myshader_shader_desc(sg_query_backend())); - - The samples in the 'sapp' subdirectory of the sokol-samples project - also use the sokol-shdc approach: - - https://github.com/floooh/sokol-samples/tree/master/sapp - - If you're planning to use sokol-shdc, you can stop reading here, instead - continue with the sokol-shdc documentation: - - https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md - - To create shaders with backend-specific shader code or binary blobs, - the sg_make_shader() function requires the following information: - - - Shader code or shader binary blobs for the vertex- and fragment- shader-stage: - - for the desktop GL backend, source code can be provided in '#version 410' or - '#version 430', version 430 is required for storage buffer support, but note - that this is not available on macOS - - for the GLES3 backend, source code must be provided in '#version 300 es' syntax - - for the D3D11 backend, shaders can be provided as source or binary blobs, the - source code should be in HLSL4.0 (for best compatibility) or alternatively - in HLSL5.0 syntax (other versions may work but are not tested), NOTE: when - shader source code is provided for the D3D11 backend, sokol-gfx will dynamically - load 'd3dcompiler_47.dll' - - for the Metal backends, shaders can be provided as source or binary blobs, the - MSL version should be in 'metal-1.1' (other versions may work but are not tested) - - for the WebGPU backend, shader must be provided as WGSL source code - - optionally the following shader-code related attributes can be provided: - - an entry function name (only on D3D11 or Metal, but not OpenGL) - - on D3D11 only, a compilation target (default is "vs_4_0" and "ps_4_0") - - - Depending on backend, information about the input vertex attributes used by the - vertex shader: - - Metal: no information needed since vertex attributes are always bound - by their attribute location defined in the shader via '[[attribute(N)]]' - - WebGPU: no information needed since vertex attributes are always - bound by their attribute location defined in the shader via `@location(N)` - - GLSL: vertex attribute names can be optionally provided, in that case their - location will be looked up by name, otherwise, the vertex attribute location - can be defined with 'layout(location = N)', PLEASE NOTE that the name-lookup method - may be removed at some point - - D3D11: a 'semantic name' and 'semantic index' must be provided for each vertex - attribute, e.g. if the vertex attribute is defined as 'TEXCOORD1' in the shader, - the semantic name would be 'TEXCOORD', and the semantic index would be '1' - - - Information about each uniform block used in the shader: - - The size of the uniform block in number of bytes. - - A memory layout hint (currently 'native' or 'std140') where 'native' defines a - backend-specific memory layout which shouldn't be used for cross-platform code. - Only std140 guarantees a backend-agnostic memory layout. - - For GLSL only: a description of the internal uniform block layout, which maps - member types and their offsets on the CPU side to uniform variable names - in the GLSL shader - - please also NOTE the documentation sections about UNIFORM DATA LAYOUT - and CROSS-BACKEND COMMON UNIFORM DATA LAYOUT below! - - - A description of each storage buffer used in the shader: - - a boolean 'readonly' flag, note that currently only - readonly storage buffers are supported - - note that storage buffers are not supported on all backends - and platforms - - - A description of each texture/image used in the shader: - - the expected image type: - - SG_IMAGETYPE_2D - - SG_IMAGETYPE_CUBE - - SG_IMAGETYPE_3D - - SG_IMAGETYPE_ARRAY - - the expected 'image sample type': - - SG_IMAGESAMPLETYPE_FLOAT - - SG_IMAGESAMPLETYPE_DEPTH - - SG_IMAGESAMPLETYPE_SINT - - SG_IMAGESAMPLETYPE_UINT - - SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT - - a flag whether the texture is expected to be multisampled - (currently it's not supported to fetch data from multisampled - textures in shaders, but this is planned for a later time) - - - A description of each texture sampler used in the shader: - - SG_SAMPLERTYPE_FILTERING, - - SG_SAMPLERTYPE_NONFILTERING, - - SG_SAMPLERTYPE_COMPARISON, - - - An array of 'image-sampler-pairs' used by the shader to sample textures, - for D3D11, Metal and WebGPU this is used for validation purposes to check - whether the texture and sampler are compatible with each other (especially - WebGPU is very picky about combining the correct - texture-sample-type with the correct sampler-type). For GLSL an - additional 'combined-image-sampler name' must be provided because 'OpenGL - style GLSL' cannot handle separate texture and sampler objects, but still - groups them into a traditional GLSL 'sampler object'. - - Compatibility rules for image-sample-type vs sampler-type are as follows: - - - SG_IMAGESAMPLETYPE_FLOAT => (SG_SAMPLERTYPE_FILTERING or SG_SAMPLERTYPE_NONFILTERING) - - SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT => SG_SAMPLERTYPE_NONFILTERING - - SG_IMAGESAMPLETYPE_SINT => SG_SAMPLERTYPE_NONFILTERING - - SG_IMAGESAMPLETYPE_UINT => SG_SAMPLERTYPE_NONFILTERING - - SG_IMAGESAMPLETYPE_DEPTH => SG_SAMPLERTYPE_COMPARISON - - For example code of how to create backend-specific shader objects, - please refer to the following samples: - - - for D3D11: https://github.com/floooh/sokol-samples/tree/master/d3d11 - - for Metal: https://github.com/floooh/sokol-samples/tree/master/metal - - for OpenGL: https://github.com/floooh/sokol-samples/tree/master/glfw - - for GLES3: https://github.com/floooh/sokol-samples/tree/master/html5 - - for WebGPI: https://github.com/floooh/sokol-samples/tree/master/wgpu - - - ON SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT AND SG_SAMPLERTYPE_NONFILTERING - ======================================================================== - The WebGPU backend introduces the concept of 'unfilterable-float' textures, - which can only be combined with 'nonfiltering' samplers (this is a restriction - specific to WebGPU, but since the same sokol-gfx code should work across - all backend, the sokol-gfx validation layer also enforces this restriction - - the alternative would be undefined behaviour in some backend APIs on - some devices). - - The background is that some mobile devices (most notably iOS devices) can - not perform linear filtering when sampling textures with certain pixel - formats, most notable the 32F formats: - - - SG_PIXELFORMAT_R32F - - SG_PIXELFORMAT_RG32F - - SG_PIXELFORMAT_RGBA32F - - The information of whether a shader is going to be used with such an - unfilterable-float texture must already be provided in the sg_shader_desc - struct when creating the shader (see the above section "ON SHADER CREATION"). - - If you are using the sokol-shdc shader compiler, the information whether a - texture/sampler binding expects an 'unfilterable-float/nonfiltering' - texture/sampler combination cannot be inferred from the shader source - alone, you'll need to provide this hint via annotation-tags. For instance - here is an example from the ozz-skin-sapp.c sample shader which samples an - RGBA32F texture with skinning matrices in the vertex shader: - - ```glsl - @image_sample_type joint_tex unfilterable_float - uniform texture2D joint_tex; - @sampler_type smp nonfiltering - uniform sampler smp; - ``` - - This will result in SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT and - SG_SAMPLERTYPE_NONFILTERING being written to the code-generated - sg_shader_desc struct. - - - UNIFORM DATA LAYOUT: - ==================== - NOTE: if you use the sokol-shdc shader compiler tool, you don't need to worry - about the following details. - - The data that's passed into the sg_apply_uniforms() function must adhere to - specific layout rules so that the GPU shader finds the uniform block - items at the right offset. - - For the D3D11 and Metal backends, sokol-gfx only cares about the size of uniform - blocks, but not about the internal layout. The data will just be copied into - a uniform/constant buffer in a single operation and it's up you to arrange the - CPU-side layout so that it matches the GPU side layout. This also means that with - the D3D11 and Metal backends you are not limited to a 'cross-platform' subset - of uniform variable types. - - If you ever only use one of the D3D11, Metal *or* WebGPU backend, you can stop reading here. - - For the GL backends, the internal layout of uniform blocks matters though, - and you are limited to a small number of uniform variable types. This is - because sokol-gfx must be able to locate the uniform block members in order - to upload them to the GPU with glUniformXXX() calls. - - To describe the uniform block layout to sokol-gfx, the following information - must be passed to the sg_make_shader() call in the sg_shader_desc struct: - - - a hint about the used packing rule (either SG_UNIFORMLAYOUT_NATIVE or - SG_UNIFORMLAYOUT_STD140) - - a list of the uniform block members types in the correct order they - appear on the CPU side - - For example if the GLSL shader has the following uniform declarations: - - uniform mat4 mvp; - uniform vec2 offset0; - uniform vec2 offset1; - uniform vec2 offset2; - - ...and on the CPU side, there's a similar C struct: - - typedef struct { - float mvp[16]; - float offset0[2]; - float offset1[2]; - float offset2[2]; - } params_t; - - ...the uniform block description in the sg_shader_desc must look like this: - - sg_shader_desc desc = { - .vs.uniform_blocks[0] = { - .size = sizeof(params_t), - .layout = SG_UNIFORMLAYOUT_NATIVE, // this is the default and can be omitted - .uniforms = { - // order must be the same as in 'params_t': - [0] = { .name = "mvp", .type = SG_UNIFORMTYPE_MAT4 }, - [1] = { .name = "offset0", .type = SG_UNIFORMTYPE_VEC2 }, - [2] = { .name = "offset1", .type = SG_UNIFORMTYPE_VEC2 }, - [3] = { .name = "offset2", .type = SG_UNIFORMTYPE_VEC2 }, - } - } - }; - - With this information sokol-gfx can now compute the correct offsets of the data items - within the uniform block struct. - - The SG_UNIFORMLAYOUT_NATIVE packing rule works fine if only the GL backends are used, - but for proper D3D11/Metal/GL a subset of the std140 layout must be used which is - described in the next section: - - - CROSS-BACKEND COMMON UNIFORM DATA LAYOUT - ======================================== - For cross-platform / cross-3D-backend code it is important that the same uniform block - layout on the CPU side can be used for all sokol-gfx backends. To achieve this, - a common subset of the std140 layout must be used: - - - The uniform block layout hint in sg_shader_desc must be explicitly set to - SG_UNIFORMLAYOUT_STD140. - - Only the following GLSL uniform types can be used (with their associated sokol-gfx enums): - - float => SG_UNIFORMTYPE_FLOAT - - vec2 => SG_UNIFORMTYPE_FLOAT2 - - vec3 => SG_UNIFORMTYPE_FLOAT3 - - vec4 => SG_UNIFORMTYPE_FLOAT4 - - int => SG_UNIFORMTYPE_INT - - ivec2 => SG_UNIFORMTYPE_INT2 - - ivec3 => SG_UNIFORMTYPE_INT3 - - ivec4 => SG_UNIFORMTYPE_INT4 - - mat4 => SG_UNIFORMTYPE_MAT4 - - Alignment for those types must be as follows (in bytes): - - float => 4 - - vec2 => 8 - - vec3 => 16 - - vec4 => 16 - - int => 4 - - ivec2 => 8 - - ivec3 => 16 - - ivec4 => 16 - - mat4 => 16 - - Arrays are only allowed for the following types: vec4, int4, mat4. - - Note that the HLSL cbuffer layout rules are slightly different from the - std140 layout rules, this means that the cbuffer declarations in HLSL code - must be tweaked so that the layout is compatible with std140. - - The by far easiest way to tackle the common uniform block layout problem is - to use the sokol-shdc shader cross-compiler tool! - - ON STORAGE BUFFERS - ================== - Storage buffers can be used to pass large amounts of random access structured - data from the CPU side to the shaders. They are similar to data textures, but are - more convenient to use both on the CPU and shader side since they can be accessed - in shaders as as a 1-dimensional array of struct items. - - Storage buffers are *NOT* supported on the following platform/backend combos: - - - macOS+GL (because storage buffers require GL 4.3, while macOS only goes up to GL 4.1) - - all GLES3 platforms (WebGL2, iOS, Android - with the option that support on - Android may be added at a later point) - - Currently only 'readonly' storage buffers are supported (meaning it's not possible - to write to storage buffers from shaders). - - To use storage buffers, the following steps are required: - - - write a shader which uses storage buffers (also see the example links below) - - create one or more storage buffers via sg_make_buffer() with the - buffer type SG_BUFFERTYPE_STORAGEBUFFER - - when creating a shader via sg_make_shader(), populate the sg_shader_desc - struct with binding info (when using sokol-shdc, this step will be taken care - of automatically) - - which storage buffer bind slots on the vertex- and fragment-stage - are occupied - - whether the storage buffer on that bind slot is readonly (this is currently required - to be true) - - when calling sg_apply_bindings(), apply the matching bind slots with the previously - created storage buffers - - ...and that's it. - - For more details, see the following backend-agnostic sokol samples: - - - simple vertex pulling from a storage buffer: - - C code: https://github.com/floooh/sokol-samples/blob/master/sapp/vertexpull-sapp.c - - shader: https://github.com/floooh/sokol-samples/blob/master/sapp/vertexpull-sapp.glsl - - instanced rendering via storage buffers (vertex- and instance-pulling): - - C code: https://github.com/floooh/sokol-samples/blob/master/sapp/instancing-pull-sapp.c - - shader: https://github.com/floooh/sokol-samples/blob/master/sapp/instancing-pull-sapp.glsl - - storage buffers both on the vertex- and fragment-stage: - - C code: https://github.com/floooh/sokol-samples/blob/master/sapp/sbuftex-sapp.c - - shader: https://github.com/floooh/sokol-samples/blob/master/sapp/sbuftex-sapp.glsl - - the Ozz animation sample rewritten to pull all rendering data from storage buffers: - - C code: https://github.com/floooh/sokol-samples/blob/master/sapp/ozz-storagebuffer-sapp.cc - - shader: https://github.com/floooh/sokol-samples/blob/master/sapp/ozz-storagebuffer-sapp.glsl - - ...also see the following backend-specific vertex pulling samples (those also don't use sokol-shdc): - - - D3D11: https://github.com/floooh/sokol-samples/blob/master/d3d11/vertexpulling-d3d11.c - - desktop GL: https://github.com/floooh/sokol-samples/blob/master/glfw/vertexpulling-glfw.c - - Metal: https://github.com/floooh/sokol-samples/blob/master/metal/vertexpulling-metal.c - - WebGPU: https://github.com/floooh/sokol-samples/blob/master/wgpu/vertexpulling-wgpu.c - - Storage buffer shader authoring caveats when using sokol-shdc: - - - declare a storage buffer interface block with `readonly buffer [name] { ... }` - - do NOT annotate storage buffers with `layout(...)`, sokol-shdc will take care of that - - declare a struct which describes a single array item in the storage buffer interface block - - only put a single flexible array member into the storage buffer interface block - - E.g. a complete example in 'sokol-shdc GLSL': - - ```glsl - // declare a struct: - struct sb_vertex { - vec3 pos; - vec4 color; - } - // declare a buffer interface block with a single flexible struct array: - readonly buffer vertices { - sb_vertex vtx[]; - } - // in the shader function, access the storage buffer like this: - void main() { - vec3 pos = vtx[gl_VertexIndex].pos; - ... - } - ``` - - Backend-specific storage-buffer caveats (not relevant when using sokol-shdc): - - D3D11: - - storage buffers are created as 'raw' Byte Address Buffers - (https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-intro#raw-views-of-buffers) - - in HLSL, use a ByteAddressBuffer to access the buffer content - (https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-byteaddressbuffer) - - in D3D11, storage buffers and textures share the same bind slots, sokol-gfx reserves - shader resource slots 0..15 for textures and 16..23 for storage buffers. - - e.g. in HLSL, storage buffer bindings start at register(t16) no matter the shader stage - - Metal: - - in Metal there is no internal difference between vertex-, uniform- and - storage-buffers, all are bound to the same 'buffer bind slots' with the - following reserved ranges: - - vertex shader stage: - - uniform buffers (internal): slots 0..3 - - vertex buffers: slots 4..11 - - storage buffers: slots 12..19 - - fragment shader stage: - - uniform buffers (internal): slots 0..3 - - storage buffers: slots 4..11 - - this means in MSL, storage buffer bindings start at [[buffer(12)]] in the vertex - shaders, and at [[buffer(4)]] in fragment shaders - - GL: - - the GL backend doesn't use name-lookup to find storage buffer bindings, this - means you must annotate buffers with `layout(std430, binding=N)` in GLSL - - ...where N is 0..7 in the vertex shader, and 8..15 in the fragment shader - - WebGPU: - - in WGSL, use the following bind locations for the various shader resource types: - - vertex shader stage: - - textures `@group(1) @binding(0..15)` - - samplers `@group(1) @binding(16..31)` - - storage buffers `@group(1) @binding(32..47)` - - fragment shader stage: - - textures `@group(1) @binding(48..63)` - - samplers `@group(1) @binding(64..79)` - - storage buffers `@group(1) @binding(80..95)` - - TRACE HOOKS: - ============ - sokol_gfx.h optionally allows to install "trace hook" callbacks for - each public API functions. When a public API function is called, and - a trace hook callback has been installed for this function, the - callback will be invoked with the parameters and result of the function. - This is useful for things like debugging- and profiling-tools, or - keeping track of resource creation and destruction. - - To use the trace hook feature: - - --- Define SOKOL_TRACE_HOOKS before including the implementation. - - --- Setup an sg_trace_hooks structure with your callback function - pointers (keep all function pointers you're not interested - in zero-initialized), optionally set the user_data member - in the sg_trace_hooks struct. - - --- Install the trace hooks by calling sg_install_trace_hooks(), - the return value of this function is another sg_trace_hooks - struct which contains the previously set of trace hooks. - You should keep this struct around, and call those previous - functions pointers from your own trace callbacks for proper - chaining. - - As an example of how trace hooks are used, have a look at the - imgui/sokol_gfx_imgui.h header which implements a realtime - debugging UI for sokol_gfx.h on top of Dear ImGui. - - - A NOTE ON PORTABLE PACKED VERTEX FORMATS: - ========================================= - There are two things to consider when using packed - vertex formats like UBYTE4, SHORT2, etc which need to work - across all backends: - - - D3D11 can only convert *normalized* vertex formats to - floating point during vertex fetch, normalized formats - have a trailing 'N', and are "normalized" to a range - -1.0..+1.0 (for the signed formats) or 0.0..1.0 (for the - unsigned formats): - - - SG_VERTEXFORMAT_BYTE4N - - SG_VERTEXFORMAT_UBYTE4N - - SG_VERTEXFORMAT_SHORT2N - - SG_VERTEXFORMAT_USHORT2N - - SG_VERTEXFORMAT_SHORT4N - - SG_VERTEXFORMAT_USHORT4N - - D3D11 will not convert *non-normalized* vertex formats to floating point - vertex shader inputs, those can only be uses with the *ivecn* vertex shader - input types when D3D11 is used as backend (GL and Metal can use both formats) - - - SG_VERTEXFORMAT_BYTE4, - - SG_VERTEXFORMAT_UBYTE4 - - SG_VERTEXFORMAT_SHORT2 - - SG_VERTEXFORMAT_SHORT4 - - For a vertex input layout which works on all platforms, only use the following - vertex formats, and if needed "expand" the normalized vertex shader - inputs in the vertex shader by multiplying with 127.0, 255.0, 32767.0 or - 65535.0: - - - SG_VERTEXFORMAT_FLOAT, - - SG_VERTEXFORMAT_FLOAT2, - - SG_VERTEXFORMAT_FLOAT3, - - SG_VERTEXFORMAT_FLOAT4, - - SG_VERTEXFORMAT_BYTE4N, - - SG_VERTEXFORMAT_UBYTE4N, - - SG_VERTEXFORMAT_SHORT2N, - - SG_VERTEXFORMAT_USHORT2N - - SG_VERTEXFORMAT_SHORT4N, - - SG_VERTEXFORMAT_USHORT4N - - SG_VERTEXFORMAT_UINT10_N2 - - SG_VERTEXFORMAT_HALF2 - - SG_VERTEXFORMAT_HALF4 - - - 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); - } - - ... - sg_setup(&(sg_desc){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ..., - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_gfx.h - itself though, not any allocations in OS libraries. - - - 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" - - sg_setup(&(sg_desc){ .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. 'sg' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SG_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_gfx.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-gfx like this: - - sg_setup(&(sg_desc){ - .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. - - - COMMIT LISTENERS - ================ - It's possible to hook callback functions into sokol-gfx which are called from - inside sg_commit() in unspecified order. This is mainly useful for libraries - that build on top of sokol_gfx.h to be notified about the end/start of a frame. - - To add a commit listener, call: - - static void my_commit_listener(void* user_data) { - ... - } - - bool success = sg_add_commit_listener((sg_commit_listener){ - .func = my_commit_listener, - .user_data = ..., - }); - - The function returns false if the internal array of commit listeners is full, - or the same commit listener had already been added. - - If the function returns true, my_commit_listener() will be called each frame - from inside sg_commit(). - - By default, 1024 distinct commit listeners can be added, but this number - can be tweaked in the sg_setup() call: - - sg_setup(&(sg_desc){ - .max_commit_listeners = 2048, - }); - - An sg_commit_listener item is equal to another if both the function - pointer and user_data field are equal. - - To remove a commit listener: - - bool success = sg_remove_commit_listener((sg_commit_listener){ - .func = my_commit_listener, - .user_data = ..., - }); - - ...where the .func and .user_data field are equal to a previous - sg_add_commit_listener() call. The function returns true if the commit - listener item was found and removed, and false otherwise. - - - RESOURCE CREATION AND DESTRUCTION IN DETAIL - =========================================== - The 'vanilla' way to create resource objects is with the 'make functions': - - sg_buffer sg_make_buffer(const sg_buffer_desc* desc) - sg_image sg_make_image(const sg_image_desc* desc) - sg_sampler sg_make_sampler(const sg_sampler_desc* desc) - sg_shader sg_make_shader(const sg_shader_desc* desc) - sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc) - sg_attachments sg_make_attachments(const sg_attachments_desc* desc) - - This will result in one of three cases: - - 1. The returned handle is invalid. This happens when there are no more - free slots in the resource pool for this resource type. An invalid - handle is associated with the INVALID resource state, for instance: - - sg_buffer buf = sg_make_buffer(...) - if (sg_query_buffer_state(buf) == SG_RESOURCESTATE_INVALID) { - // buffer pool is exhausted - } - - 2. The returned handle is valid, but creating the underlying resource - has failed for some reason. This results in a resource object in the - FAILED state. The reason *why* resource creation has failed differ - by resource type. Look for log messages with more details. A failed - resource state can be checked with: - - sg_buffer buf = sg_make_buffer(...) - if (sg_query_buffer_state(buf) == SG_RESOURCESTATE_FAILED) { - // creating the resource has failed - } - - 3. And finally, if everything goes right, the returned resource is - in resource state VALID and ready to use. This can be checked - with: - - sg_buffer buf = sg_make_buffer(...) - if (sg_query_buffer_state(buf) == SG_RESOURCESTATE_VALID) { - // creating the resource has failed - } - - When calling the 'make functions', the created resource goes through a number - of states: - - - INITIAL: the resource slot associated with the new resource is currently - free (technically, there is no resource yet, just an empty pool slot) - - ALLOC: a handle for the new resource has been allocated, this just means - a pool slot has been reserved. - - VALID or FAILED: in VALID state any 3D API backend resource objects have - been successfully created, otherwise if anything went wrong, the resource - will be in FAILED state. - - Sometimes it makes sense to first grab a handle, but initialize the - underlying resource at a later time. For instance when loading data - asynchronously from a slow data source, you may know what buffers and - textures are needed at an early stage of the loading process, but actually - loading the buffer or texture content can only be completed at a later time. - - For such situations, sokol-gfx resource objects can be created in two steps. - You can allocate a handle upfront with one of the 'alloc functions': - - sg_buffer sg_alloc_buffer(void) - sg_image sg_alloc_image(void) - sg_sampler sg_alloc_sampler(void) - sg_shader sg_alloc_shader(void) - sg_pipeline sg_alloc_pipeline(void) - sg_attachments sg_alloc_attachments(void) - - This will return a handle with the underlying resource object in the - ALLOC state: - - sg_image img = sg_alloc_image(); - if (sg_query_image_state(img) == SG_RESOURCESTATE_ALLOC) { - // allocating an image handle has succeeded, otherwise - // the image pool is full - } - - Such an 'incomplete' handle can be used in most sokol-gfx rendering functions - without doing any harm, sokol-gfx will simply skip any rendering operation - that involve resources which are not in VALID state. - - At a later time (for instance once the texture has completed loading - asynchronously), the resource creation can be completed by calling one of - the 'init functions', those functions take an existing resource handle and - 'desc struct': - - void sg_init_buffer(sg_buffer buf, const sg_buffer_desc* desc) - void sg_init_image(sg_image img, const sg_image_desc* desc) - void sg_init_sampler(sg_sampler smp, const sg_sampler_desc* desc) - void sg_init_shader(sg_shader shd, const sg_shader_desc* desc) - void sg_init_pipeline(sg_pipeline pip, const sg_pipeline_desc* desc) - void sg_init_attachments(sg_attachments atts, const sg_attachments_desc* desc) - - The init functions expect a resource in ALLOC state, and after the function - returns, the resource will be either in VALID or FAILED state. Calling - an 'alloc function' followed by the matching 'init function' is fully - equivalent with calling the 'make function' alone. - - Destruction can also happen as a two-step process. The 'uninit functions' - will put a resource object from the VALID or FAILED state back into the - ALLOC state: - - void sg_uninit_buffer(sg_buffer buf) - void sg_uninit_image(sg_image img) - void sg_uninit_sampler(sg_sampler smp) - void sg_uninit_shader(sg_shader shd) - void sg_uninit_pipeline(sg_pipeline pip) - void sg_uninit_attachments(sg_attachments pass) - - Calling the 'uninit functions' with a resource that is not in the VALID or - FAILED state is a no-op. - - To finally free the pool slot for recycling call the 'dealloc functions': - - void sg_dealloc_buffer(sg_buffer buf) - void sg_dealloc_image(sg_image img) - void sg_dealloc_sampler(sg_sampler smp) - void sg_dealloc_shader(sg_shader shd) - void sg_dealloc_pipeline(sg_pipeline pip) - void sg_dealloc_attachments(sg_attachments atts) - - Calling the 'dealloc functions' on a resource that's not in ALLOC state is - a no-op, but will generate a warning log message. - - Calling an 'uninit function' and 'dealloc function' in sequence is equivalent - with calling the associated 'destroy function': - - void sg_destroy_buffer(sg_buffer buf) - void sg_destroy_image(sg_image img) - void sg_destroy_sampler(sg_sampler smp) - void sg_destroy_shader(sg_shader shd) - void sg_destroy_pipeline(sg_pipeline pip) - void sg_destroy_attachments(sg_attachments atts) - - The 'destroy functions' can be called on resources in any state and generally - do the right thing (for instance if the resource is in ALLOC state, the destroy - function will be equivalent to the 'dealloc function' and skip the 'uninit part'). - - And finally to close the circle, the 'fail functions' can be called to manually - put a resource in ALLOC state into the FAILED state: - - sg_fail_buffer(sg_buffer buf) - sg_fail_image(sg_image img) - sg_fail_sampler(sg_sampler smp) - sg_fail_shader(sg_shader shd) - sg_fail_pipeline(sg_pipeline pip) - sg_fail_attachments(sg_attachments atts) - - This is recommended if anything went wrong outside of sokol-gfx during asynchronous - resource setup (for instance a file loading operation failed). In this case, - the 'fail function' should be called instead of the 'init function'. - - Calling a 'fail function' on a resource that's not in ALLOC state is a no-op, - but will generate a warning log message. - - NOTE: that two-step resource creation usually only makes sense for buffers - and images, but not for samplers, shaders, pipelines or attachments. Most notably, trying - to create a pipeline object with a shader that's not in VALID state will - trigger a validation layer error, or if the validation layer is disabled, - result in a pipeline object in FAILED state. Same when trying to create - an attachments object with invalid image objects. - - - WEBGPU CAVEATS - ============== - For a general overview and design notes of the WebGPU backend see: - - https://floooh.github.io/2023/10/16/sokol-webgpu.html - - In general, don't expect an automatic speedup when switching from the WebGL2 - backend to the WebGPU backend. Some WebGPU functions currently actually - have a higher CPU overhead than similar WebGL2 functions, leading to the - paradoxical situation that some WebGPU code may be slower than similar WebGL2 - code. - - - when writing WGSL shader code by hand, a specific bind-slot convention - must be used: - - All uniform block structs must use `@group(0)`, with up to - 4 uniform blocks per shader stage. - - Vertex shader uniform block bindings must start at `@group(0) @binding(0)` - - Fragment shader uniform blocks bindings must start at `@group(0) @binding(4)` - - All textures and samplers must use `@group(1)` and start at specific - offsets depending on resource type and shader stage. - - Vertex shader textures must start at `@group(1) @binding(0)` - - Vertex shader samplers must start at `@group(1) @binding(16)` - - Vertex shader storage buffers must start at `@group(1) @binding(32)` - - Fragment shader textures must start at `@group(1) @binding(48)` - - Fragment shader samplers must start at `@group(1) @binding(64)` - - Fragment shader storage buffers must start at `@group(1) @binding(80)` - - Note that the actual number of allowed per-stage texture- and sampler-bindings - in sokol-gfx is currently lower than the above ranges (currently only up to - 12 textures, 8 samplers and 8 storage buffers are allowed per shader stage). - - If you use sokol-shdc to generate WGSL shader code, you don't need to worry - about the above binding convention since sokol-shdc assigns bind slots - automatically. - - - The sokol-gfx WebGPU backend uses the sg_desc.uniform_buffer_size item - to allocate a single per-frame uniform buffer which must be big enough - to hold all data written by sg_apply_uniforms() during a single frame, - including a worst-case 256-byte alignment (e.g. each sg_apply_uniform - call will cost 256 bytes of uniform buffer size). The default size - is 4 MB, which is enough for 16384 sg_apply_uniform() calls per - frame (assuming the uniform data 'payload' is less than 256 bytes - per call). These rules are the same as for the Metal backend, so if - you are already using the Metal backend you'll be fine. - - - sg_apply_bindings(): the sokol-gfx WebGPU backend implements a bindgroup - cache to prevent excessive creation and destruction of BindGroup objects - when calling sg_apply_bindings(). The number of slots in the bindgroups - cache is defined in sg_desc.wgpu_bindgroups_cache_size when calling - sg_setup. The cache size must be a power-of-2 number, with the default being - 1024. The bindgroups cache behaviour can be observed by calling the new - function sg_query_frame_stats(), where the following struct items are - of interest: - - .wgpu.num_bindgroup_cache_hits - .wgpu.num_bindgroup_cache_misses - .wgpu.num_bindgroup_cache_collisions - .wgpu_num_bindgroup_cache_invalidates - .wgpu.num_bindgroup_cache_vs_hash_key_mismatch - - The value to pay attention to is `.wgpu.num_bindgroup_cache_collisions`, - if this number if consistently higher than a few percent of the - .wgpu.num_set_bindgroup value, it might be a good idea to bump the - bindgroups cache size to the next power-of-2. - - - sg_apply_viewport(): WebGPU currently has a unique restriction that viewport - rectangles must be contained entirely within the framebuffer. As a shitty - workaround sokol_gfx.h will clip incoming viewport rectangles against - the framebuffer, but this will distort the clipspace-to-screenspace mapping. - There's no proper way to handle this inside sokol_gfx.h, this must be fixed - in a future WebGPU update. - - - The sokol shader compiler generally adds `diagnostic(off, derivative_uniformity);` - into the WGSL output. Currently only the Chrome WebGPU implementation seems - to recognize this. - - - The vertex format SG_VERTEXFORMAT_UINT10_N2 is currently not supported because - WebGPU lacks a matching vertex format (this is currently being worked on though, - as soon as the vertex format shows up in webgpu.h, sokol_gfx.h will add support. - - - Likewise, the following sokol-gfx vertex formats are not supported in WebGPU: - R16, R16SN, RG16, RG16SN, RGBA16, RGBA16SN and all PVRTC compressed format. - Unlike unsupported vertex formats, unsupported pixel formats can be queried - in cross-backend code via sg_query_pixel_format() though. - - - The Emscripten WebGPU shim currently doesn't support the Closure minification - post-link-step (e.g. currently the emcc argument '--closure 1' or '--closure 2' - will generate broken Javascript code. - - - sokol-gfx requires the WebGPU device feature `depth32float-stencil8` to be enabled - (this should be widely supported) - - - sokol-gfx expects that the WebGPU device feature `float32-filterable` to *not* be - enabled (since this would exclude all iOS devices) - - - 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. -*/ -#define SOKOL_GFX_INCLUDED (1) -#include // size_t -#include -#include - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_GFX_API_DECL) -#define SOKOL_GFX_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_GFX_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GFX_IMPL) -#define SOKOL_GFX_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_GFX_API_DECL __declspec(dllimport) -#else -#define SOKOL_GFX_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - Resource id typedefs: - - sg_buffer: vertex- and index-buffers - sg_image: images used as textures and render targets - sg_sampler sampler object describing how a texture is sampled in a shader - sg_shader: vertex- and fragment-shaders and shader interface information - sg_pipeline: associated shader and vertex-layouts, and render states - sg_attachments: a baked collection of render pass attachment images - - Instead of pointers, resource creation functions return a 32-bit - number which uniquely identifies the resource object. - - The 32-bit resource id is split into a 16-bit pool index in the lower bits, - and a 16-bit 'generation counter' in the upper bits. The index allows fast - pool lookups, and combined with the generation-counter it allows to detect - 'dangling accesses' (trying to use an object which no longer exists, and - its pool slot has been reused for a new object) - - The resource ids are wrapped into a strongly-typed struct so that - trying to pass an incompatible resource id is a compile error. -*/ -typedef struct sg_buffer { uint32_t id; } sg_buffer; -typedef struct sg_image { uint32_t id; } sg_image; -typedef struct sg_sampler { uint32_t id; } sg_sampler; -typedef struct sg_shader { uint32_t id; } sg_shader; -typedef struct sg_pipeline { uint32_t id; } sg_pipeline; -typedef struct sg_attachments { uint32_t id; } sg_attachments; - -/* - sg_range is a pointer-size-pair struct used to pass memory blobs into - sokol-gfx. When initialized from a value type (array or struct), you can - use the SG_RANGE() macro to build an sg_range struct. For functions which - take either a sg_range pointer, or a (C++) sg_range reference, use the - SG_RANGE_REF macro as a solution which compiles both in C and C++. -*/ -typedef struct sg_range { - const void* ptr; - size_t size; -} sg_range; - -// disabling this for every includer isn't great, but the warnings are also quite pointless -#if defined(_MSC_VER) -#pragma warning(disable:4221) // /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' -#pragma warning(disable:4204) // VS2015: nonstandard extension used: non-constant aggregate initializer -#endif -#if defined(__cplusplus) -#define SG_RANGE(x) sg_range{ &x, sizeof(x) } -#define SG_RANGE_REF(x) sg_range{ &x, sizeof(x) } -#else -#define SG_RANGE(x) (sg_range){ &x, sizeof(x) } -#define SG_RANGE_REF(x) &(sg_range){ &x, sizeof(x) } -#endif - -// various compile-time constants -enum { - SG_INVALID_ID = 0, - SG_NUM_SHADER_STAGES = 2, - SG_NUM_INFLIGHT_FRAMES = 2, - SG_MAX_COLOR_ATTACHMENTS = 4, - SG_MAX_VERTEX_BUFFERS = 8, - SG_MAX_SHADERSTAGE_IMAGES = 12, - SG_MAX_SHADERSTAGE_SAMPLERS = 8, - SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS = 12, - SG_MAX_SHADERSTAGE_STORAGEBUFFERS = 8, - SG_MAX_SHADERSTAGE_UBS = 4, - SG_MAX_UB_MEMBERS = 16, - SG_MAX_VERTEX_ATTRIBUTES = 16, - SG_MAX_MIPMAPS = 16, - SG_MAX_TEXTUREARRAY_LAYERS = 128 -}; - -/* - sg_color - - An RGBA color value. -*/ -typedef struct sg_color { float r, g, b, a; } sg_color; - -/* - sg_backend - - The active 3D-API backend, use the function sg_query_backend() - to get the currently active backend. -*/ -typedef enum sg_backend { - SG_BACKEND_GLCORE, - SG_BACKEND_GLES3, - SG_BACKEND_D3D11, - SG_BACKEND_METAL_IOS, - SG_BACKEND_METAL_MACOS, - SG_BACKEND_METAL_SIMULATOR, - SG_BACKEND_WGPU, - SG_BACKEND_DUMMY, -} sg_backend; - -/* - sg_pixel_format - - sokol_gfx.h basically uses the same pixel formats as WebGPU, since these - are supported on most newer GPUs. - - A pixelformat name consist of three parts: - - - components (R, RG, RGB or RGBA) - - bit width per component (8, 16 or 32) - - component data type: - - unsigned normalized (no postfix) - - signed normalized (SN postfix) - - unsigned integer (UI postfix) - - signed integer (SI postfix) - - float (F postfix) - - Not all pixel formats can be used for everything, call sg_query_pixelformat() - to inspect the capabilities of a given pixelformat. The function returns - an sg_pixelformat_info struct with the following members: - - - sample: the pixelformat can be sampled as texture at least with - nearest filtering - - filter: the pixelformat can be samples as texture with linear - filtering - - render: the pixelformat can be used for render targets - - blend: blending is supported when using the pixelformat for - render targets - - msaa: multisample-antialiasing is supported when using the - pixelformat for render targets - - depth: the pixelformat can be used for depth-stencil attachments - - compressed: this is a block-compressed format - - bytes_per_pixel: the numbers of bytes in a pixel (0 for compressed formats) - - The default pixel format for texture images is SG_PIXELFORMAT_RGBA8. - - The default pixel format for render target images is platform-dependent - and taken from the sg_environment struct passed into sg_setup(). Typically - the default formats are: - - - for the Metal, D3D11 and WebGPU backends: SG_PIXELFORMAT_BGRA8 - - for GL backends: SG_PIXELFORMAT_RGBA8 -*/ -typedef enum sg_pixel_format { - _SG_PIXELFORMAT_DEFAULT, // value 0 reserved for default-init - SG_PIXELFORMAT_NONE, - - SG_PIXELFORMAT_R8, - SG_PIXELFORMAT_R8SN, - SG_PIXELFORMAT_R8UI, - SG_PIXELFORMAT_R8SI, - - SG_PIXELFORMAT_R16, - SG_PIXELFORMAT_R16SN, - SG_PIXELFORMAT_R16UI, - SG_PIXELFORMAT_R16SI, - SG_PIXELFORMAT_R16F, - SG_PIXELFORMAT_RG8, - SG_PIXELFORMAT_RG8SN, - SG_PIXELFORMAT_RG8UI, - SG_PIXELFORMAT_RG8SI, - - SG_PIXELFORMAT_R32UI, - SG_PIXELFORMAT_R32SI, - SG_PIXELFORMAT_R32F, - SG_PIXELFORMAT_RG16, - SG_PIXELFORMAT_RG16SN, - SG_PIXELFORMAT_RG16UI, - SG_PIXELFORMAT_RG16SI, - SG_PIXELFORMAT_RG16F, - SG_PIXELFORMAT_RGBA8, - SG_PIXELFORMAT_SRGB8A8, - SG_PIXELFORMAT_RGBA8SN, - SG_PIXELFORMAT_RGBA8UI, - SG_PIXELFORMAT_RGBA8SI, - SG_PIXELFORMAT_BGRA8, - SG_PIXELFORMAT_RGB10A2, - SG_PIXELFORMAT_RG11B10F, - SG_PIXELFORMAT_RGB9E5, - - SG_PIXELFORMAT_RG32UI, - SG_PIXELFORMAT_RG32SI, - SG_PIXELFORMAT_RG32F, - SG_PIXELFORMAT_RGBA16, - SG_PIXELFORMAT_RGBA16SN, - SG_PIXELFORMAT_RGBA16UI, - SG_PIXELFORMAT_RGBA16SI, - SG_PIXELFORMAT_RGBA16F, - - SG_PIXELFORMAT_RGBA32UI, - SG_PIXELFORMAT_RGBA32SI, - SG_PIXELFORMAT_RGBA32F, - - // NOTE: when adding/removing pixel formats before DEPTH, also update sokol_app.h/_SAPP_PIXELFORMAT_* - SG_PIXELFORMAT_DEPTH, - SG_PIXELFORMAT_DEPTH_STENCIL, - - // NOTE: don't put any new compressed format in front of here - SG_PIXELFORMAT_BC1_RGBA, - SG_PIXELFORMAT_BC2_RGBA, - SG_PIXELFORMAT_BC3_RGBA, - SG_PIXELFORMAT_BC3_SRGBA, - SG_PIXELFORMAT_BC4_R, - SG_PIXELFORMAT_BC4_RSN, - SG_PIXELFORMAT_BC5_RG, - SG_PIXELFORMAT_BC5_RGSN, - SG_PIXELFORMAT_BC6H_RGBF, - SG_PIXELFORMAT_BC6H_RGBUF, - SG_PIXELFORMAT_BC7_RGBA, - SG_PIXELFORMAT_BC7_SRGBA, - SG_PIXELFORMAT_PVRTC_RGB_2BPP, // FIXME: deprecated - SG_PIXELFORMAT_PVRTC_RGB_4BPP, // FIXME: deprecated - SG_PIXELFORMAT_PVRTC_RGBA_2BPP, // FIXME: deprecated - SG_PIXELFORMAT_PVRTC_RGBA_4BPP, // FIXME: deprecated - SG_PIXELFORMAT_ETC2_RGB8, - SG_PIXELFORMAT_ETC2_SRGB8, - SG_PIXELFORMAT_ETC2_RGB8A1, - SG_PIXELFORMAT_ETC2_RGBA8, - SG_PIXELFORMAT_ETC2_SRGB8A8, - SG_PIXELFORMAT_EAC_R11, - SG_PIXELFORMAT_EAC_R11SN, - SG_PIXELFORMAT_EAC_RG11, - SG_PIXELFORMAT_EAC_RG11SN, - - SG_PIXELFORMAT_ASTC_4x4_RGBA, - SG_PIXELFORMAT_ASTC_4x4_SRGBA, - - _SG_PIXELFORMAT_NUM, - _SG_PIXELFORMAT_FORCE_U32 = 0x7FFFFFFF -} sg_pixel_format; - -/* - Runtime information about a pixel format, returned - by sg_query_pixelformat(). -*/ -typedef struct sg_pixelformat_info { - bool sample; // pixel format can be sampled in shaders at least with nearest filtering - bool filter; // pixel format can be sampled with linear filtering - bool render; // pixel format can be used as render target - bool blend; // alpha-blending is supported - bool msaa; // pixel format can be used as MSAA render target - bool depth; // pixel format is a depth format - bool compressed; // true if this is a hardware-compressed format - int bytes_per_pixel; // NOTE: this is 0 for compressed formats, use sg_query_row_pitch() / sg_query_surface_pitch() as alternative -} sg_pixelformat_info; - -/* - Runtime information about available optional features, - returned by sg_query_features() -*/ -typedef struct sg_features { - bool origin_top_left; // framebuffer and texture origin is in top left corner - bool image_clamp_to_border; // border color and clamp-to-border UV-wrap mode is supported - bool mrt_independent_blend_state; // multiple-render-target rendering can use per-render-target blend state - bool mrt_independent_write_mask; // multiple-render-target rendering can use per-render-target color write masks - bool storage_buffer; // storage buffers are supported -} sg_features; - -/* - Runtime information about resource limits, returned by sg_query_limit() -*/ -typedef struct sg_limits { - int max_image_size_2d; // max width/height of SG_IMAGETYPE_2D images - int max_image_size_cube; // max width/height of SG_IMAGETYPE_CUBE images - int max_image_size_3d; // max width/height/depth of SG_IMAGETYPE_3D images - int max_image_size_array; // max width/height of SG_IMAGETYPE_ARRAY images - int max_image_array_layers; // max number of layers in SG_IMAGETYPE_ARRAY images - int max_vertex_attrs; // max number of vertex attributes, clamped to SG_MAX_VERTEX_ATTRIBUTES - int gl_max_vertex_uniform_components; // <= GL_MAX_VERTEX_UNIFORM_COMPONENTS (only on GL backends) - int gl_max_combined_texture_image_units; // <= GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (only on GL backends) -} sg_limits; - -/* - sg_resource_state - - The current state of a resource in its resource pool. - Resources start in the INITIAL state, which means the - pool slot is unoccupied and can be allocated. When a resource is - created, first an id is allocated, and the resource pool slot - is set to state ALLOC. After allocation, the resource is - initialized, which may result in the VALID or FAILED state. The - reason why allocation and initialization are separate is because - some resource types (e.g. buffers and images) might be asynchronously - initialized by the user application. If a resource which is not - in the VALID state is attempted to be used for rendering, rendering - operations will silently be dropped. - - The special INVALID state is returned in sg_query_xxx_state() if no - resource object exists for the provided resource id. -*/ -typedef enum sg_resource_state { - SG_RESOURCESTATE_INITIAL, - SG_RESOURCESTATE_ALLOC, - SG_RESOURCESTATE_VALID, - SG_RESOURCESTATE_FAILED, - SG_RESOURCESTATE_INVALID, - _SG_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF -} sg_resource_state; - -/* - sg_usage - - A resource usage hint describing the update strategy of - buffers and images. This is used in the sg_buffer_desc.usage - and sg_image_desc.usage members when creating buffers - and images: - - SG_USAGE_IMMUTABLE: the resource will never be updated with - new data, instead the content of the - resource must be provided on creation - SG_USAGE_DYNAMIC: the resource will be updated infrequently - with new data (this could range from "once - after creation", to "quite often but not - every frame") - SG_USAGE_STREAM: the resource will be updated each frame - with new content - - The rendering backends use this hint to prevent that the - CPU needs to wait for the GPU when attempting to update - a resource that might be currently accessed by the GPU. - - Resource content is updated with the functions sg_update_buffer() or - sg_append_buffer() for buffer objects, and sg_update_image() for image - objects. For the sg_update_*() functions, only one update is allowed per - frame and resource object, while sg_append_buffer() can be called - multiple times per frame on the same buffer. The application must update - all data required for rendering (this means that the update data can be - smaller than the resource size, if only a part of the overall resource - size is used for rendering, you only need to make sure that the data that - *is* used is valid). - - The default usage is SG_USAGE_IMMUTABLE. -*/ -typedef enum sg_usage { - _SG_USAGE_DEFAULT, // value 0 reserved for default-init - SG_USAGE_IMMUTABLE, - SG_USAGE_DYNAMIC, - SG_USAGE_STREAM, - _SG_USAGE_NUM, - _SG_USAGE_FORCE_U32 = 0x7FFFFFFF -} sg_usage; - -/* - sg_buffer_type - - Indicates whether a buffer will be bound as vertex-, - index- or storage-buffer. - - Used in the sg_buffer_desc.type member when creating a buffer. - - The default value is SG_BUFFERTYPE_VERTEXBUFFER. -*/ -typedef enum sg_buffer_type { - _SG_BUFFERTYPE_DEFAULT, // value 0 reserved for default-init - SG_BUFFERTYPE_VERTEXBUFFER, - SG_BUFFERTYPE_INDEXBUFFER, - SG_BUFFERTYPE_STORAGEBUFFER, - _SG_BUFFERTYPE_NUM, - _SG_BUFFERTYPE_FORCE_U32 = 0x7FFFFFFF -} sg_buffer_type; - -/* - sg_index_type - - Indicates whether indexed rendering (fetching vertex-indices from an - index buffer) is used, and if yes, the index data type (16- or 32-bits). - This is used in the sg_pipeline_desc.index_type member when creating a - pipeline object. - - The default index type is SG_INDEXTYPE_NONE. -*/ -typedef enum sg_index_type { - _SG_INDEXTYPE_DEFAULT, // value 0 reserved for default-init - SG_INDEXTYPE_NONE, - SG_INDEXTYPE_UINT16, - SG_INDEXTYPE_UINT32, - _SG_INDEXTYPE_NUM, - _SG_INDEXTYPE_FORCE_U32 = 0x7FFFFFFF -} sg_index_type; - -/* - sg_image_type - - Indicates the basic type of an image object (2D-texture, cubemap, - 3D-texture or 2D-array-texture). Used in the sg_image_desc.type member when - creating an image, and in sg_shader_image_desc to describe a sampled texture - in the shader (both must match and will be checked in the validation layer - when calling sg_apply_bindings). - - The default image type when creating an image is SG_IMAGETYPE_2D. -*/ -typedef enum sg_image_type { - _SG_IMAGETYPE_DEFAULT, // value 0 reserved for default-init - SG_IMAGETYPE_2D, - SG_IMAGETYPE_CUBE, - SG_IMAGETYPE_3D, - SG_IMAGETYPE_ARRAY, - _SG_IMAGETYPE_NUM, - _SG_IMAGETYPE_FORCE_U32 = 0x7FFFFFFF -} sg_image_type; - -/* - sg_image_sample_type - - The basic data type of a texture sample as expected by a shader. - Must be provided in sg_shader_image_desc and used by the validation - layer in sg_apply_bindings() to check if the provided image object - is compatible with what the shader expects. Apart from the sokol-gfx - validation layer, WebGPU is the only backend API which actually requires - matching texture and sampler type to be provided upfront for validation - (other 3D APIs treat texture/sampler type mismatches as undefined behaviour). - - NOTE that the following texture pixel formats require the use - of SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT, combined with a sampler - of type SG_SAMPLERTYPE_NONFILTERING: - - - SG_PIXELFORMAT_R32F - - SG_PIXELFORMAT_RG32F - - SG_PIXELFORMAT_RGBA32F - - (when using sokol-shdc, also check out the meta tags `@image_sample_type` - and `@sampler_type`) -*/ -typedef enum sg_image_sample_type { - _SG_IMAGESAMPLETYPE_DEFAULT, // value 0 reserved for default-init - SG_IMAGESAMPLETYPE_FLOAT, - SG_IMAGESAMPLETYPE_DEPTH, - SG_IMAGESAMPLETYPE_SINT, - SG_IMAGESAMPLETYPE_UINT, - SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT, - _SG_IMAGESAMPLETYPE_NUM, - _SG_IMAGESAMPLETYPE_FORCE_U32 = 0x7FFFFFFF -} sg_image_sample_type; - -/* - sg_sampler_type - - The basic type of a texture sampler (sampling vs comparison) as - defined in a shader. Must be provided in sg_shader_sampler_desc. - - sg_image_sample_type and sg_sampler_type for a texture/sampler - pair must be compatible with each other, specifically only - the following pairs are allowed: - - - SG_IMAGESAMPLETYPE_FLOAT => (SG_SAMPLERTYPE_FILTERING or SG_SAMPLERTYPE_NONFILTERING) - - SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT => SG_SAMPLERTYPE_NONFILTERING - - SG_IMAGESAMPLETYPE_SINT => SG_SAMPLERTYPE_NONFILTERING - - SG_IMAGESAMPLETYPE_UINT => SG_SAMPLERTYPE_NONFILTERING - - SG_IMAGESAMPLETYPE_DEPTH => SG_SAMPLERTYPE_COMPARISON -*/ -typedef enum sg_sampler_type { - _SG_SAMPLERTYPE_DEFAULT, - SG_SAMPLERTYPE_FILTERING, - SG_SAMPLERTYPE_NONFILTERING, - SG_SAMPLERTYPE_COMPARISON, - _SG_SAMPLERTYPE_NUM, - _SG_SAMPLERTYPE_FORCE_U32, -} sg_sampler_type; - -/* - sg_cube_face - - The cubemap faces. Use these as indices in the sg_image_desc.content - array. -*/ -typedef enum sg_cube_face { - SG_CUBEFACE_POS_X, - SG_CUBEFACE_NEG_X, - SG_CUBEFACE_POS_Y, - SG_CUBEFACE_NEG_Y, - SG_CUBEFACE_POS_Z, - SG_CUBEFACE_NEG_Z, - SG_CUBEFACE_NUM, - _SG_CUBEFACE_FORCE_U32 = 0x7FFFFFFF -} sg_cube_face; - -/* - sg_shader_stage - - There are 2 shader stages: vertex- and fragment-shader-stage. - Each shader stage - - - SG_MAX_SHADERSTAGE_UBS slots for applying uniform data - - SG_MAX_SHADERSTAGE_IMAGES slots for images used as textures - - SG_MAX_SHADERSTAGE_SAMPLERS slots for texture samplers - - SG_MAX_SHADERSTAGE_STORAGEBUFFERS slots for storage buffer bindings -*/ -typedef enum sg_shader_stage { - SG_SHADERSTAGE_VS, - SG_SHADERSTAGE_FS, - _SG_SHADERSTAGE_FORCE_U32 = 0x7FFFFFFF -} sg_shader_stage; - -/* - sg_primitive_type - - This is the common subset of 3D primitive types supported across all 3D - APIs. This is used in the sg_pipeline_desc.primitive_type member when - creating a pipeline object. - - The default primitive type is SG_PRIMITIVETYPE_TRIANGLES. -*/ -typedef enum sg_primitive_type { - _SG_PRIMITIVETYPE_DEFAULT, // value 0 reserved for default-init - SG_PRIMITIVETYPE_POINTS, - SG_PRIMITIVETYPE_LINES, - SG_PRIMITIVETYPE_LINE_STRIP, - SG_PRIMITIVETYPE_TRIANGLES, - SG_PRIMITIVETYPE_TRIANGLE_STRIP, - _SG_PRIMITIVETYPE_NUM, - _SG_PRIMITIVETYPE_FORCE_U32 = 0x7FFFFFFF -} sg_primitive_type; - -/* - sg_filter - - The filtering mode when sampling a texture image. This is - used in the sg_sampler_desc.min_filter, sg_sampler_desc.mag_filter - and sg_sampler_desc.mipmap_filter members when creating a sampler object. - - For the default is SG_FILTER_NEAREST. -*/ -typedef enum sg_filter { - _SG_FILTER_DEFAULT, // value 0 reserved for default-init - SG_FILTER_NEAREST, - SG_FILTER_LINEAR, - _SG_FILTER_NUM, - _SG_FILTER_FORCE_U32 = 0x7FFFFFFF -} sg_filter; - -/* - sg_wrap - - The texture coordinates wrapping mode when sampling a texture - image. This is used in the sg_image_desc.wrap_u, .wrap_v - and .wrap_w members when creating an image. - - The default wrap mode is SG_WRAP_REPEAT. - - NOTE: SG_WRAP_CLAMP_TO_BORDER is not supported on all backends - and platforms. To check for support, call sg_query_features() - and check the "clamp_to_border" boolean in the returned - sg_features struct. - - Platforms which don't support SG_WRAP_CLAMP_TO_BORDER will silently fall back - to SG_WRAP_CLAMP_TO_EDGE without a validation error. -*/ -typedef enum sg_wrap { - _SG_WRAP_DEFAULT, // value 0 reserved for default-init - SG_WRAP_REPEAT, - SG_WRAP_CLAMP_TO_EDGE, - SG_WRAP_CLAMP_TO_BORDER, - SG_WRAP_MIRRORED_REPEAT, - _SG_WRAP_NUM, - _SG_WRAP_FORCE_U32 = 0x7FFFFFFF -} sg_wrap; - -/* - sg_border_color - - The border color to use when sampling a texture, and the UV wrap - mode is SG_WRAP_CLAMP_TO_BORDER. - - The default border color is SG_BORDERCOLOR_OPAQUE_BLACK -*/ -typedef enum sg_border_color { - _SG_BORDERCOLOR_DEFAULT, // value 0 reserved for default-init - SG_BORDERCOLOR_TRANSPARENT_BLACK, - SG_BORDERCOLOR_OPAQUE_BLACK, - SG_BORDERCOLOR_OPAQUE_WHITE, - _SG_BORDERCOLOR_NUM, - _SG_BORDERCOLOR_FORCE_U32 = 0x7FFFFFFF -} sg_border_color; - -/* - sg_vertex_format - - The data type of a vertex component. This is used to describe - the layout of vertex data when creating a pipeline object. -*/ -typedef enum sg_vertex_format { - SG_VERTEXFORMAT_INVALID, - SG_VERTEXFORMAT_FLOAT, - SG_VERTEXFORMAT_FLOAT2, - SG_VERTEXFORMAT_FLOAT3, - SG_VERTEXFORMAT_FLOAT4, - SG_VERTEXFORMAT_BYTE4, - SG_VERTEXFORMAT_BYTE4N, - SG_VERTEXFORMAT_UBYTE4, - SG_VERTEXFORMAT_UBYTE4N, - SG_VERTEXFORMAT_SHORT2, - SG_VERTEXFORMAT_SHORT2N, - SG_VERTEXFORMAT_USHORT2N, - SG_VERTEXFORMAT_SHORT4, - SG_VERTEXFORMAT_SHORT4N, - SG_VERTEXFORMAT_USHORT4N, - SG_VERTEXFORMAT_UINT10_N2, - SG_VERTEXFORMAT_HALF2, - SG_VERTEXFORMAT_HALF4, - _SG_VERTEXFORMAT_NUM, - _SG_VERTEXFORMAT_FORCE_U32 = 0x7FFFFFFF -} sg_vertex_format; - -/* - sg_vertex_step - - Defines whether the input pointer of a vertex input stream is advanced - 'per vertex' or 'per instance'. The default step-func is - SG_VERTEXSTEP_PER_VERTEX. SG_VERTEXSTEP_PER_INSTANCE is used with - instanced-rendering. - - The vertex-step is part of the vertex-layout definition - when creating pipeline objects. -*/ -typedef enum sg_vertex_step { - _SG_VERTEXSTEP_DEFAULT, // value 0 reserved for default-init - SG_VERTEXSTEP_PER_VERTEX, - SG_VERTEXSTEP_PER_INSTANCE, - _SG_VERTEXSTEP_NUM, - _SG_VERTEXSTEP_FORCE_U32 = 0x7FFFFFFF -} sg_vertex_step; - -/* - sg_uniform_type - - The data type of a uniform block member. This is used to - describe the internal layout of uniform blocks when creating - a shader object. -*/ -typedef enum sg_uniform_type { - SG_UNIFORMTYPE_INVALID, - SG_UNIFORMTYPE_FLOAT, - SG_UNIFORMTYPE_FLOAT2, - SG_UNIFORMTYPE_FLOAT3, - SG_UNIFORMTYPE_FLOAT4, - SG_UNIFORMTYPE_INT, - SG_UNIFORMTYPE_INT2, - SG_UNIFORMTYPE_INT3, - SG_UNIFORMTYPE_INT4, - SG_UNIFORMTYPE_MAT4, - _SG_UNIFORMTYPE_NUM, - _SG_UNIFORMTYPE_FORCE_U32 = 0x7FFFFFFF -} sg_uniform_type; - -/* - sg_uniform_layout - - A hint for the interior memory layout of uniform blocks. This is - only really relevant for the GL backend where the internal layout - of uniform blocks must be known to sokol-gfx. For all other backends the - internal memory layout of uniform blocks doesn't matter, sokol-gfx - will just pass uniform data as a single memory blob to the - 3D backend. - - SG_UNIFORMLAYOUT_NATIVE (default) - Native layout means that a 'backend-native' memory layout - is used. For the GL backend this means that uniforms - are packed tightly in memory (e.g. there are no padding - bytes). - - SG_UNIFORMLAYOUT_STD140 - The memory layout is a subset of std140. Arrays are only - allowed for the FLOAT4, INT4 and MAT4. Alignment is as - is as follows: - - FLOAT, INT: 4 byte alignment - FLOAT2, INT2: 8 byte alignment - FLOAT3, INT3: 16 byte alignment(!) - FLOAT4, INT4: 16 byte alignment - MAT4: 16 byte alignment - FLOAT4[], INT4[]: 16 byte alignment - - The overall size of the uniform block must be a multiple - of 16. - - For more information search for 'UNIFORM DATA LAYOUT' in the documentation block - at the start of the header. -*/ -typedef enum sg_uniform_layout { - _SG_UNIFORMLAYOUT_DEFAULT, // value 0 reserved for default-init - SG_UNIFORMLAYOUT_NATIVE, // default: layout depends on currently active backend - SG_UNIFORMLAYOUT_STD140, // std140: memory layout according to std140 - _SG_UNIFORMLAYOUT_NUM, - _SG_UNIFORMLAYOUT_FORCE_U32 = 0x7FFFFFFF -} sg_uniform_layout; - -/* - sg_cull_mode - - The face-culling mode, this is used in the - sg_pipeline_desc.cull_mode member when creating a - pipeline object. - - The default cull mode is SG_CULLMODE_NONE -*/ -typedef enum sg_cull_mode { - _SG_CULLMODE_DEFAULT, // value 0 reserved for default-init - SG_CULLMODE_NONE, - SG_CULLMODE_FRONT, - SG_CULLMODE_BACK, - _SG_CULLMODE_NUM, - _SG_CULLMODE_FORCE_U32 = 0x7FFFFFFF -} sg_cull_mode; - -/* - sg_face_winding - - The vertex-winding rule that determines a front-facing primitive. This - is used in the member sg_pipeline_desc.face_winding - when creating a pipeline object. - - The default winding is SG_FACEWINDING_CW (clockwise) -*/ -typedef enum sg_face_winding { - _SG_FACEWINDING_DEFAULT, // value 0 reserved for default-init - SG_FACEWINDING_CCW, - SG_FACEWINDING_CW, - _SG_FACEWINDING_NUM, - _SG_FACEWINDING_FORCE_U32 = 0x7FFFFFFF -} sg_face_winding; - -/* - sg_compare_func - - The compare-function for configuring depth- and stencil-ref tests - in pipeline objects, and for texture samplers which perform a comparison - instead of regular sampling operation. - - sg_pipeline_desc - .depth - .compare - .stencil - .front.compare - .back.compar - - sg_sampler_desc - .compare - - The default compare func for depth- and stencil-tests is - SG_COMPAREFUNC_ALWAYS. - - The default compare func for sampler is SG_COMPAREFUNC_NEVER. -*/ -typedef enum sg_compare_func { - _SG_COMPAREFUNC_DEFAULT, // value 0 reserved for default-init - SG_COMPAREFUNC_NEVER, - SG_COMPAREFUNC_LESS, - SG_COMPAREFUNC_EQUAL, - SG_COMPAREFUNC_LESS_EQUAL, - SG_COMPAREFUNC_GREATER, - SG_COMPAREFUNC_NOT_EQUAL, - SG_COMPAREFUNC_GREATER_EQUAL, - SG_COMPAREFUNC_ALWAYS, - _SG_COMPAREFUNC_NUM, - _SG_COMPAREFUNC_FORCE_U32 = 0x7FFFFFFF -} sg_compare_func; - -/* - sg_stencil_op - - The operation performed on a currently stored stencil-value when a - comparison test passes or fails. This is used when creating a pipeline - object in the members: - - sg_pipeline_desc - .stencil - .front - .fail_op - .depth_fail_op - .pass_op - .back - .fail_op - .depth_fail_op - .pass_op - - The default value is SG_STENCILOP_KEEP. -*/ -typedef enum sg_stencil_op { - _SG_STENCILOP_DEFAULT, // value 0 reserved for default-init - SG_STENCILOP_KEEP, - SG_STENCILOP_ZERO, - SG_STENCILOP_REPLACE, - SG_STENCILOP_INCR_CLAMP, - SG_STENCILOP_DECR_CLAMP, - SG_STENCILOP_INVERT, - SG_STENCILOP_INCR_WRAP, - SG_STENCILOP_DECR_WRAP, - _SG_STENCILOP_NUM, - _SG_STENCILOP_FORCE_U32 = 0x7FFFFFFF -} sg_stencil_op; - -/* - sg_blend_factor - - The source and destination factors in blending operations. - This is used in the following members when creating a pipeline object: - - sg_pipeline_desc - .colors[i] - .blend - .src_factor_rgb - .dst_factor_rgb - .src_factor_alpha - .dst_factor_alpha - - The default value is SG_BLENDFACTOR_ONE for source - factors, and SG_BLENDFACTOR_ZERO for destination factors. -*/ -typedef enum sg_blend_factor { - _SG_BLENDFACTOR_DEFAULT, // value 0 reserved for default-init - SG_BLENDFACTOR_ZERO, - SG_BLENDFACTOR_ONE, - SG_BLENDFACTOR_SRC_COLOR, - SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR, - SG_BLENDFACTOR_SRC_ALPHA, - SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, - SG_BLENDFACTOR_DST_COLOR, - SG_BLENDFACTOR_ONE_MINUS_DST_COLOR, - SG_BLENDFACTOR_DST_ALPHA, - SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA, - SG_BLENDFACTOR_SRC_ALPHA_SATURATED, - SG_BLENDFACTOR_BLEND_COLOR, - SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR, - SG_BLENDFACTOR_BLEND_ALPHA, - SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA, - _SG_BLENDFACTOR_NUM, - _SG_BLENDFACTOR_FORCE_U32 = 0x7FFFFFFF -} sg_blend_factor; - -/* - sg_blend_op - - Describes how the source and destination values are combined in the - fragment blending operation. It is used in the following members when - creating a pipeline object: - - sg_pipeline_desc - .colors[i] - .blend - .op_rgb - .op_alpha - - The default value is SG_BLENDOP_ADD. -*/ -typedef enum sg_blend_op { - _SG_BLENDOP_DEFAULT, // value 0 reserved for default-init - SG_BLENDOP_ADD, - SG_BLENDOP_SUBTRACT, - SG_BLENDOP_REVERSE_SUBTRACT, - _SG_BLENDOP_NUM, - _SG_BLENDOP_FORCE_U32 = 0x7FFFFFFF -} sg_blend_op; - -/* - sg_color_mask - - Selects the active color channels when writing a fragment color to the - framebuffer. This is used in the members - sg_pipeline_desc.colors[i].write_mask when creating a pipeline object. - - The default colormask is SG_COLORMASK_RGBA (write all colors channels) - - NOTE: since the color mask value 0 is reserved for the default value - (SG_COLORMASK_RGBA), use SG_COLORMASK_NONE if all color channels - should be disabled. -*/ -typedef enum sg_color_mask { - _SG_COLORMASK_DEFAULT = 0, // value 0 reserved for default-init - SG_COLORMASK_NONE = 0x10, // special value for 'all channels disabled - SG_COLORMASK_R = 0x1, - SG_COLORMASK_G = 0x2, - SG_COLORMASK_RG = 0x3, - SG_COLORMASK_B = 0x4, - SG_COLORMASK_RB = 0x5, - SG_COLORMASK_GB = 0x6, - SG_COLORMASK_RGB = 0x7, - SG_COLORMASK_A = 0x8, - SG_COLORMASK_RA = 0x9, - SG_COLORMASK_GA = 0xA, - SG_COLORMASK_RGA = 0xB, - SG_COLORMASK_BA = 0xC, - SG_COLORMASK_RBA = 0xD, - SG_COLORMASK_GBA = 0xE, - SG_COLORMASK_RGBA = 0xF, - _SG_COLORMASK_FORCE_U32 = 0x7FFFFFFF -} sg_color_mask; - -/* - sg_load_action - - Defines the load action that should be performed at the start of a render pass: - - SG_LOADACTION_CLEAR: clear the render target - SG_LOADACTION_LOAD: load the previous content of the render target - SG_LOADACTION_DONTCARE: leave the render target in an undefined state - - This is used in the sg_pass_action structure. - - The default load action for all pass attachments is SG_LOADACTION_CLEAR, - with the values rgba = { 0.5f, 0.5f, 0.5f, 1.0f }, depth=1.0f and stencil=0. - - If you want to override the default behaviour, it is important to not - only set the clear color, but the 'action' field as well (as long as this - is _SG_LOADACTION_DEFAULT, the value fields will be ignored). -*/ -typedef enum sg_load_action { - _SG_LOADACTION_DEFAULT, - SG_LOADACTION_CLEAR, - SG_LOADACTION_LOAD, - SG_LOADACTION_DONTCARE, - _SG_LOADACTION_FORCE_U32 = 0x7FFFFFFF -} sg_load_action; - -/* - sg_store_action - - Defines the store action that be performed at the end of a render pass: - - SG_STOREACTION_STORE: store the rendered content to the color attachment image - SG_STOREACTION_DONTCARE: allows the GPU to discard the rendered content -*/ -typedef enum sg_store_action { - _SG_STOREACTION_DEFAULT, - SG_STOREACTION_STORE, - SG_STOREACTION_DONTCARE, - _SG_STOREACTION_FORCE_U32 = 0x7FFFFFFF -} sg_store_action; - - -/* - sg_pass_action - - The sg_pass_action struct defines the actions to be performed - at the start and end of a render pass. - - - at the start of the pass: whether the render targets should be cleared, - loaded with their previous content, or start in an undefined state - - for clear operations: the clear value (color, depth, or stencil values) - - at the end of the pass: whether the rendering result should be - stored back into the render target or discarded -*/ -typedef struct sg_color_attachment_action { - sg_load_action load_action; // default: SG_LOADACTION_CLEAR - sg_store_action store_action; // default: SG_STOREACTION_STORE - sg_color clear_value; // default: { 0.5f, 0.5f, 0.5f, 1.0f } -} sg_color_attachment_action; - -typedef struct sg_depth_attachment_action { - sg_load_action load_action; // default: SG_LOADACTION_CLEAR - sg_store_action store_action; // default: SG_STOREACTION_DONTCARE - float clear_value; // default: 1.0 -} sg_depth_attachment_action; - -typedef struct sg_stencil_attachment_action { - sg_load_action load_action; // default: SG_LOADACTION_CLEAR - sg_store_action store_action; // default: SG_STOREACTION_DONTCARE - uint8_t clear_value; // default: 0 -} sg_stencil_attachment_action; - -typedef struct sg_pass_action { - sg_color_attachment_action colors[SG_MAX_COLOR_ATTACHMENTS]; - sg_depth_attachment_action depth; - sg_stencil_attachment_action stencil; -} sg_pass_action; - -/* - sg_swapchain - - Used in sg_begin_pass() to provide details about an external swapchain - (pixel formats, sample count and backend-API specific render surface objects). - - The following information must be provided: - - - the width and height of the swapchain surfaces in number of pixels, - - the pixel format of the render- and optional msaa-resolve-surface - - the pixel format of the optional depth- or depth-stencil-surface - - the MSAA sample count for the render and depth-stencil surface - - If the pixel formats and MSAA sample counts are left zero-initialized, - their defaults are taken from the sg_environment struct provided in the - sg_setup() call. - - The width and height *must* be > 0. - - Additionally the following backend API specific objects must be passed in - as 'type erased' void pointers: - - GL: on all GL backends, a GL framebuffer object must be provided. This - can be zero for the default framebuffer. - - D3D11: - - an ID3D11RenderTargetView for the rendering surface, without - MSAA rendering this surface will also be displayed - - an optional ID3D11DepthStencilView for the depth- or depth/stencil - buffer surface - - when MSAA rendering is used, another ID3D11RenderTargetView - which serves as MSAA resolve target and will be displayed - - WebGPU (same as D3D11, except different types) - - a WGPUTextureView for the rendering surface, without - MSAA rendering this surface will also be displayed - - an optional WGPUTextureView for the depth- or depth/stencil - buffer surface - - when MSAA rendering is used, another WGPUTextureView - which serves as MSAA resolve target and will be displayed - - Metal (NOTE that the rolves of provided surfaces is slightly different - than on D3D11 or WebGPU in case of MSAA vs non-MSAA rendering): - - - A current CAMetalDrawable (NOT an MTLDrawable!) which will be presented. - This will either be rendered to directly (if no MSAA is used), or serve - as MSAA-resolve target. - - an optional MTLTexture for the depth- or depth-stencil buffer - - an optional multisampled MTLTexture which serves as intermediate - rendering surface which will then be resolved into the - CAMetalDrawable. - - NOTE that for Metal you must use an ObjC __bridge cast to - properly tunnel the ObjC object handle through a C void*, e.g.: - - swapchain.metal.current_drawable = (__bridge const void*) [mtkView currentDrawable]; - - On all other backends you shouldn't need to mess with the reference count. - - It's a good practice to write a helper function which returns an initialized - sg_swapchain structs, which can then be plugged directly into - sg_pass.swapchain. Look at the function sglue_swapchain() in the sokol_glue.h - as an example. -*/ -typedef struct sg_metal_swapchain { - const void* current_drawable; // CAMetalDrawable (NOT MTLDrawable!!!) - const void* depth_stencil_texture; // MTLTexture - const void* msaa_color_texture; // MTLTexture -} sg_metal_swapchain; - -typedef struct sg_d3d11_swapchain { - const void* render_view; // ID3D11RenderTargetView - const void* resolve_view; // ID3D11RenderTargetView - const void* depth_stencil_view; // ID3D11DepthStencilView -} sg_d3d11_swapchain; - -typedef struct sg_wgpu_swapchain { - const void* render_view; // WGPUTextureView - const void* resolve_view; // WGPUTextureView - const void* depth_stencil_view; // WGPUTextureView -} sg_wgpu_swapchain; - -typedef struct sg_gl_swapchain { - uint32_t framebuffer; // GL framebuffer object -} sg_gl_swapchain; - -typedef struct sg_swapchain { - int width; - int height; - int sample_count; - sg_pixel_format color_format; - sg_pixel_format depth_format; - sg_metal_swapchain metal; - sg_d3d11_swapchain d3d11; - sg_wgpu_swapchain wgpu; - sg_gl_swapchain gl; -} sg_swapchain; - -/* - sg_pass - - The sg_pass structure is passed as argument into the sg_begin_pass() - function. - - For an offscreen rendering pass, an sg_pass_action struct and sg_attachments - object must be provided, and for swapchain passes, and sg_pass_action and - an sg_swapchain struct. It is an error to provide both an sg_attachments - handle and an initialized sg_swapchain struct in the same sg_begin_pass(). - - An sg_begin_pass() call for an offscreen pass would look like this (where - `attachments` is an sg_attachments handle): - - sg_begin_pass(&(sg_pass){ - .action = { ... }, - .attachments = attachments, - }); - - ...and a swapchain render pass would look like this (using the sokol_glue.h - helper function sglue_swapchain() which gets the swapchain properties from - sokol_app.h): - - sg_begin_pass(&(sg_pass){ - .action = { ... }, - .swapchain = sglue_swapchain(), - }); - - You can also omit the .action object to get default pass action behaviour - (clear to color=grey, depth=1 and stencil=0). -*/ -typedef struct sg_pass { - uint32_t _start_canary; - sg_pass_action action; - sg_attachments attachments; - sg_swapchain swapchain; - const char* label; - uint32_t _end_canary; -} sg_pass; - -/* - sg_bindings - - The sg_bindings structure defines the resource binding slots - of the sokol_gfx render pipeline, used as argument to the - sg_apply_bindings() function. - - A resource binding struct contains: - - - 1..N vertex buffers - - 0..N vertex buffer offsets - - 0..1 index buffers - - 0..1 index buffer offsets - - 0..N vertex shader stage images - - 0..N vertex shader stage samplers - - 0..N vertex shader storage buffers - - 0..N fragment shader stage images - - 0..N fragment shader stage samplers - - 0..N fragment shader storage buffers - - For the max number of bindings, see the constant definitions: - - - SG_MAX_VERTEX_BUFFERS - - SG_MAX_SHADERSTAGE_IMAGES - - SG_MAX_SHADERSTAGE_SAMPLERS - - SG_MAX_SHADERSTAGE_STORAGEBUFFERS - - The optional buffer offsets can be used to put different unrelated - chunks of vertex- and/or index-data into the same buffer objects. -*/ -typedef struct sg_stage_bindings { - sg_image images[SG_MAX_SHADERSTAGE_IMAGES]; - sg_sampler samplers[SG_MAX_SHADERSTAGE_SAMPLERS]; - sg_buffer storage_buffers[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; -} sg_stage_bindings; - -typedef struct sg_bindings { - uint32_t _start_canary; - sg_buffer vertex_buffers[SG_MAX_VERTEX_BUFFERS]; - int vertex_buffer_offsets[SG_MAX_VERTEX_BUFFERS]; - sg_buffer index_buffer; - int index_buffer_offset; - sg_stage_bindings vs; - sg_stage_bindings fs; - uint32_t _end_canary; -} sg_bindings; - -/* - sg_buffer_desc - - Creation parameters for sg_buffer objects, used in the - sg_make_buffer() call. - - The default configuration is: - - .size: 0 (*must* be >0 for buffers without data) - .type: SG_BUFFERTYPE_VERTEXBUFFER - .usage: SG_USAGE_IMMUTABLE - .data.ptr 0 (*must* be valid for immutable buffers) - .data.size 0 (*must* be > 0 for immutable buffers) - .label 0 (optional string label) - - For immutable buffers which are initialized with initial data, - keep the .size item zero-initialized, and set the size together with the - pointer to the initial data in the .data item. - - For mutable buffers without initial data, keep the .data item - zero-initialized, and set the buffer size in the .size item instead. - - You can also set both size values, but currently both size values must - be identical (this may change in the future when the dynamic resource - management may become more flexible). - - ADVANCED TOPIC: Injecting native 3D-API buffers: - - The following struct members allow to inject your own GL, Metal - or D3D11 buffers into sokol_gfx: - - .gl_buffers[SG_NUM_INFLIGHT_FRAMES] - .mtl_buffers[SG_NUM_INFLIGHT_FRAMES] - .d3d11_buffer - - You must still provide all other struct items except the .data item, and - these must match the creation parameters of the native buffers you - provide. For SG_USAGE_IMMUTABLE, only provide a single native 3D-API - buffer, otherwise you need to provide SG_NUM_INFLIGHT_FRAMES buffers - (only for GL and Metal, not D3D11). Providing multiple buffers for GL and - Metal is necessary because sokol_gfx will rotate through them when - calling sg_update_buffer() to prevent lock-stalls. - - Note that it is expected that immutable injected buffer have already been - initialized with content, and the .content member must be 0! - - Also you need to call sg_reset_state_cache() after calling native 3D-API - functions, and before calling any sokol_gfx function. -*/ -typedef struct sg_buffer_desc { - uint32_t _start_canary; - size_t size; - sg_buffer_type type; - sg_usage usage; - sg_range data; - const char* label; - // optionally inject backend-specific resources - uint32_t gl_buffers[SG_NUM_INFLIGHT_FRAMES]; - const void* mtl_buffers[SG_NUM_INFLIGHT_FRAMES]; - const void* d3d11_buffer; - const void* wgpu_buffer; - uint32_t _end_canary; -} sg_buffer_desc; - -/* - sg_image_data - - Defines the content of an image through a 2D array of sg_range structs. - The first array dimension is the cubemap face, and the second array - dimension the mipmap level. -*/ -typedef struct sg_image_data { - sg_range subimage[SG_CUBEFACE_NUM][SG_MAX_MIPMAPS]; -} sg_image_data; - -/* - sg_image_desc - - Creation parameters for sg_image objects, used in the sg_make_image() call. - - The default configuration is: - - .type: SG_IMAGETYPE_2D - .render_target: false - .width 0 (must be set to >0) - .height 0 (must be set to >0) - .num_slices 1 (3D textures: depth; array textures: number of layers) - .num_mipmaps: 1 - .usage: SG_USAGE_IMMUTABLE - .pixel_format: SG_PIXELFORMAT_RGBA8 for textures, or sg_desc.environment.defaults.color_format for render targets - .sample_count: 1 for textures, or sg_desc.environment.defaults.sample_count for render targets - .data an sg_image_data struct to define the initial content - .label 0 (optional string label for trace hooks) - - Q: Why is the default sample_count for render targets identical with the - "default sample count" from sg_desc.environment.defaults.sample_count? - - A: So that it matches the default sample count in pipeline objects. Even - though it is a bit strange/confusing that offscreen render targets by default - get the same sample count as 'default swapchains', but it's better that - an offscreen render target created with default parameters matches - a pipeline object created with default parameters. - - NOTE: - - Images with usage SG_USAGE_IMMUTABLE must be fully initialized by - providing a valid .data member which points to initialization data. - - ADVANCED TOPIC: Injecting native 3D-API textures: - - The following struct members allow to inject your own GL, Metal or D3D11 - textures into sokol_gfx: - - .gl_textures[SG_NUM_INFLIGHT_FRAMES] - .mtl_textures[SG_NUM_INFLIGHT_FRAMES] - .d3d11_texture - .d3d11_shader_resource_view - .wgpu_texture - .wgpu_texture_view - - For GL, you can also specify the texture target or leave it empty to use - the default texture target for the image type (GL_TEXTURE_2D for - SG_IMAGETYPE_2D etc) - - For D3D11 and WebGPU, either only provide a texture, or both a texture and - shader-resource-view / texture-view object. If you want to use access the - injected texture in a shader you *must* provide a shader-resource-view. - - The same rules apply as for injecting native buffers (see sg_buffer_desc - documentation for more details). -*/ -typedef struct sg_image_desc { - uint32_t _start_canary; - sg_image_type type; - bool render_target; - int width; - int height; - int num_slices; - int num_mipmaps; - sg_usage usage; - sg_pixel_format pixel_format; - int sample_count; - sg_image_data data; - const char* label; - // optionally inject backend-specific resources - uint32_t gl_textures[SG_NUM_INFLIGHT_FRAMES]; - uint32_t gl_texture_target; - const void* mtl_textures[SG_NUM_INFLIGHT_FRAMES]; - const void* d3d11_texture; - const void* d3d11_shader_resource_view; - const void* wgpu_texture; - const void* wgpu_texture_view; - uint32_t _end_canary; -} sg_image_desc; - -/* - sg_sampler_desc - - Creation parameters for sg_sampler objects, used in the sg_make_sampler() call - - .min_filter: SG_FILTER_NEAREST - .mag_filter: SG_FILTER_NEAREST - .mipmap_filter SG_FILTER_NEAREST - .wrap_u: SG_WRAP_REPEAT - .wrap_v: SG_WRAP_REPEAT - .wrap_w: SG_WRAP_REPEAT (only SG_IMAGETYPE_3D) - .min_lod 0.0f - .max_lod FLT_MAX - .border_color SG_BORDERCOLOR_OPAQUE_BLACK - .compare SG_COMPAREFUNC_NEVER - .max_anisotropy 1 (must be 1..16) - -*/ -typedef struct sg_sampler_desc { - uint32_t _start_canary; - sg_filter min_filter; - sg_filter mag_filter; - sg_filter mipmap_filter; - sg_wrap wrap_u; - sg_wrap wrap_v; - sg_wrap wrap_w; - float min_lod; - float max_lod; - sg_border_color border_color; - sg_compare_func compare; - uint32_t max_anisotropy; - const char* label; - // optionally inject backend-specific resources - uint32_t gl_sampler; - const void* mtl_sampler; - const void* d3d11_sampler; - const void* wgpu_sampler; - uint32_t _end_canary; -} sg_sampler_desc; - -/* - sg_shader_desc - - The structure sg_shader_desc defines all creation parameters for shader - programs, used as input to the sg_make_shader() function: - - - reflection information for vertex attributes (vertex shader inputs): - - vertex attribute name (only optionally used by GLES3 and GL) - - a semantic name and index (required for D3D11) - - for each shader-stage (vertex and fragment): - - the shader source or bytecode - - an optional entry function name - - an optional compile target (only for D3D11 when source is provided, - defaults are "vs_4_0" and "ps_4_0") - - reflection info for each uniform block used by the shader stage: - - the size of the uniform block in bytes - - a memory layout hint (native vs std140, only required for GL backends) - - reflection info for each uniform block member (only required for GL backends): - - member name - - member type (SG_UNIFORMTYPE_xxx) - - if the member is an array, the number of array items - - reflection info for textures used in the shader stage: - - the image type (SG_IMAGETYPE_xxx) - - the image-sample type (SG_IMAGESAMPLETYPE_xxx, default is SG_IMAGESAMPLETYPE_FLOAT) - - whether the shader expects a multisampled texture - - reflection info for samplers used in the shader stage: - - the sampler type (SG_SAMPLERTYPE_xxx) - - reflection info for each image-sampler-pair used by the shader: - - the texture slot of the involved texture - - the sampler slot of the involved sampler - - for GLSL only: the name of the combined image-sampler object - - reflection info for each storage-buffer used by the shader: - - whether the storage buffer is readonly (currently this - must be true) - - For all GL backends, shader source-code must be provided. For D3D11 and Metal, - either shader source-code or byte-code can be provided. - - For D3D11, if source code is provided, the d3dcompiler_47.dll will be loaded - on demand. If this fails, shader creation will fail. When compiling HLSL - source code, you can provide an optional target string via - sg_shader_stage_desc.d3d11_target, the default target is "vs_4_0" for the - vertex shader stage and "ps_4_0" for the pixel shader stage. -*/ -typedef struct sg_shader_attr_desc { - const char* name; // GLSL vertex attribute name (optional) - const char* sem_name; // HLSL semantic name - int sem_index; // HLSL semantic index -} sg_shader_attr_desc; - -typedef struct sg_shader_uniform_desc { - const char* name; - sg_uniform_type type; - int array_count; -} sg_shader_uniform_desc; - -typedef struct sg_shader_uniform_block_desc { - size_t size; - sg_uniform_layout layout; - sg_shader_uniform_desc uniforms[SG_MAX_UB_MEMBERS]; -} sg_shader_uniform_block_desc; - -typedef struct sg_shader_storage_buffer_desc { - bool used; - bool readonly; -} sg_shader_storage_buffer_desc; - -typedef struct sg_shader_image_desc { - bool used; - bool multisampled; - sg_image_type image_type; - sg_image_sample_type sample_type; -} sg_shader_image_desc; - -typedef struct sg_shader_sampler_desc { - bool used; - sg_sampler_type sampler_type; -} sg_shader_sampler_desc; - -typedef struct sg_shader_image_sampler_pair_desc { - bool used; - int image_slot; - int sampler_slot; - const char* glsl_name; -} sg_shader_image_sampler_pair_desc; - -typedef struct sg_shader_stage_desc { - const char* source; - sg_range bytecode; - const char* entry; - const char* d3d11_target; - sg_shader_uniform_block_desc uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; - sg_shader_storage_buffer_desc storage_buffers[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; - sg_shader_image_desc images[SG_MAX_SHADERSTAGE_IMAGES]; - sg_shader_sampler_desc samplers[SG_MAX_SHADERSTAGE_SAMPLERS]; - sg_shader_image_sampler_pair_desc image_sampler_pairs[SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]; -} sg_shader_stage_desc; - -typedef struct sg_shader_desc { - uint32_t _start_canary; - sg_shader_attr_desc attrs[SG_MAX_VERTEX_ATTRIBUTES]; - sg_shader_stage_desc vs; - sg_shader_stage_desc fs; - const char* label; - uint32_t _end_canary; -} sg_shader_desc; - -/* - sg_pipeline_desc - - The sg_pipeline_desc struct defines all creation parameters for an - sg_pipeline object, used as argument to the sg_make_pipeline() function: - - - the vertex layout for all input vertex buffers - - a shader object - - the 3D primitive type (points, lines, triangles, ...) - - the index type (none, 16- or 32-bit) - - all the fixed-function-pipeline state (depth-, stencil-, blend-state, etc...) - - If the vertex data has no gaps between vertex components, you can omit - the .layout.buffers[].stride and layout.attrs[].offset items (leave them - default-initialized to 0), sokol-gfx will then compute the offsets and - strides from the vertex component formats (.layout.attrs[].format). - Please note that ALL vertex attribute offsets must be 0 in order for the - automatic offset computation to kick in. - - The default configuration is as follows: - - .shader: 0 (must be initialized with a valid sg_shader id!) - .layout: - .buffers[]: vertex buffer layouts - .stride: 0 (if no stride is given it will be computed) - .step_func SG_VERTEXSTEP_PER_VERTEX - .step_rate 1 - .attrs[]: vertex attribute declarations - .buffer_index 0 the vertex buffer bind slot - .offset 0 (offsets can be omitted if the vertex layout has no gaps) - .format SG_VERTEXFORMAT_INVALID (must be initialized!) - .depth: - .pixel_format: sg_desc.context.depth_format - .compare: SG_COMPAREFUNC_ALWAYS - .write_enabled: false - .bias: 0.0f - .bias_slope_scale: 0.0f - .bias_clamp: 0.0f - .stencil: - .enabled: false - .front/back: - .compare: SG_COMPAREFUNC_ALWAYS - .fail_op: SG_STENCILOP_KEEP - .depth_fail_op: SG_STENCILOP_KEEP - .pass_op: SG_STENCILOP_KEEP - .read_mask: 0 - .write_mask: 0 - .ref: 0 - .color_count 1 - .colors[0..color_count] - .pixel_format sg_desc.context.color_format - .write_mask: SG_COLORMASK_RGBA - .blend: - .enabled: false - .src_factor_rgb: SG_BLENDFACTOR_ONE - .dst_factor_rgb: SG_BLENDFACTOR_ZERO - .op_rgb: SG_BLENDOP_ADD - .src_factor_alpha: SG_BLENDFACTOR_ONE - .dst_factor_alpha: SG_BLENDFACTOR_ZERO - .op_alpha: SG_BLENDOP_ADD - .primitive_type: SG_PRIMITIVETYPE_TRIANGLES - .index_type: SG_INDEXTYPE_NONE - .cull_mode: SG_CULLMODE_NONE - .face_winding: SG_FACEWINDING_CW - .sample_count: sg_desc.context.sample_count - .blend_color: (sg_color) { 0.0f, 0.0f, 0.0f, 0.0f } - .alpha_to_coverage_enabled: false - .label 0 (optional string label for trace hooks) -*/ -typedef struct sg_vertex_buffer_layout_state { - int stride; - sg_vertex_step step_func; - int step_rate; -} sg_vertex_buffer_layout_state; - -typedef struct sg_vertex_attr_state { - int buffer_index; - int offset; - sg_vertex_format format; -} sg_vertex_attr_state; - -typedef struct sg_vertex_layout_state { - sg_vertex_buffer_layout_state buffers[SG_MAX_VERTEX_BUFFERS]; - sg_vertex_attr_state attrs[SG_MAX_VERTEX_ATTRIBUTES]; -} sg_vertex_layout_state; - -typedef struct sg_stencil_face_state { - sg_compare_func compare; - sg_stencil_op fail_op; - sg_stencil_op depth_fail_op; - sg_stencil_op pass_op; -} sg_stencil_face_state; - -typedef struct sg_stencil_state { - bool enabled; - sg_stencil_face_state front; - sg_stencil_face_state back; - uint8_t read_mask; - uint8_t write_mask; - uint8_t ref; -} sg_stencil_state; - -typedef struct sg_depth_state { - sg_pixel_format pixel_format; - sg_compare_func compare; - bool write_enabled; - float bias; - float bias_slope_scale; - float bias_clamp; -} sg_depth_state; - -typedef struct sg_blend_state { - bool enabled; - sg_blend_factor src_factor_rgb; - sg_blend_factor dst_factor_rgb; - sg_blend_op op_rgb; - sg_blend_factor src_factor_alpha; - sg_blend_factor dst_factor_alpha; - sg_blend_op op_alpha; -} sg_blend_state; - -typedef struct sg_color_target_state { - sg_pixel_format pixel_format; - sg_color_mask write_mask; - sg_blend_state blend; -} sg_color_target_state; - -typedef struct sg_pipeline_desc { - uint32_t _start_canary; - sg_shader shader; - sg_vertex_layout_state layout; - sg_depth_state depth; - sg_stencil_state stencil; - int color_count; - sg_color_target_state colors[SG_MAX_COLOR_ATTACHMENTS]; - sg_primitive_type primitive_type; - sg_index_type index_type; - sg_cull_mode cull_mode; - sg_face_winding face_winding; - int sample_count; - sg_color blend_color; - bool alpha_to_coverage_enabled; - const char* label; - uint32_t _end_canary; -} sg_pipeline_desc; - -/* - sg_attachments_desc - - Creation parameters for an sg_attachments object, used as argument to the - sg_make_attachments() function. - - An attachments object bundles 0..4 color attachments, 0..4 msaa-resolve - attachments, and none or one depth-stencil attachmente for use - in a render pass. At least one color attachment or one depth-stencil - attachment must be provided (no color attachment and a depth-stencil - attachment is useful for a depth-only render pass). - - Each attachment definition consists of an image object, and two additional indices - describing which subimage the pass will render into: one mipmap index, and if the image - is a cubemap, array-texture or 3D-texture, the face-index, array-layer or - depth-slice. - - All attachments must have the same width and height. - - All color attachments and the depth-stencil attachment must have the - same sample count. - - If a resolve attachment is set, an MSAA-resolve operation from the - associated color attachment image into the resolve attachment image will take - place in the sg_end_pass() function. In this case, the color attachment - must have a (sample_count>1), and the resolve attachment a - (sample_count==1). The resolve attachment also must have the same pixel - format as the color attachment. - - NOTE that MSAA depth-stencil attachments cannot be msaa-resolved! -*/ -typedef struct sg_attachment_desc { - sg_image image; - int mip_level; - int slice; // cube texture: face; array texture: layer; 3D texture: slice -} sg_attachment_desc; - -typedef struct sg_attachments_desc { - uint32_t _start_canary; - sg_attachment_desc colors[SG_MAX_COLOR_ATTACHMENTS]; - sg_attachment_desc resolves[SG_MAX_COLOR_ATTACHMENTS]; - sg_attachment_desc depth_stencil; - const char* label; - uint32_t _end_canary; -} sg_attachments_desc; - -/* - sg_trace_hooks - - Installable callback functions to keep track of the sokol-gfx calls, - this is useful for debugging, or keeping track of resource creation - and destruction. - - Trace hooks are installed with sg_install_trace_hooks(), this returns - another sg_trace_hooks struct with the previous set of - trace hook function pointers. These should be invoked by the - new trace hooks to form a proper call chain. -*/ -typedef struct sg_trace_hooks { - void* user_data; - void (*reset_state_cache)(void* user_data); - void (*make_buffer)(const sg_buffer_desc* desc, sg_buffer result, void* user_data); - void (*make_image)(const sg_image_desc* desc, sg_image result, void* user_data); - void (*make_sampler)(const sg_sampler_desc* desc, sg_sampler result, void* user_data); - void (*make_shader)(const sg_shader_desc* desc, sg_shader result, void* user_data); - void (*make_pipeline)(const sg_pipeline_desc* desc, sg_pipeline result, void* user_data); - void (*make_attachments)(const sg_attachments_desc* desc, sg_attachments result, void* user_data); - void (*destroy_buffer)(sg_buffer buf, void* user_data); - void (*destroy_image)(sg_image img, void* user_data); - void (*destroy_sampler)(sg_sampler smp, void* user_data); - void (*destroy_shader)(sg_shader shd, void* user_data); - void (*destroy_pipeline)(sg_pipeline pip, void* user_data); - void (*destroy_attachments)(sg_attachments atts, void* user_data); - void (*update_buffer)(sg_buffer buf, const sg_range* data, void* user_data); - void (*update_image)(sg_image img, const sg_image_data* data, void* user_data); - void (*append_buffer)(sg_buffer buf, const sg_range* data, int result, void* user_data); - void (*begin_pass)(const sg_pass* pass, void* user_data); - void (*apply_viewport)(int x, int y, int width, int height, bool origin_top_left, void* user_data); - void (*apply_scissor_rect)(int x, int y, int width, int height, bool origin_top_left, void* user_data); - void (*apply_pipeline)(sg_pipeline pip, void* user_data); - void (*apply_bindings)(const sg_bindings* bindings, void* user_data); - void (*apply_uniforms)(sg_shader_stage stage, int ub_index, const sg_range* data, void* user_data); - void (*draw)(int base_element, int num_elements, int num_instances, void* user_data); - void (*end_pass)(void* user_data); - void (*commit)(void* user_data); - void (*alloc_buffer)(sg_buffer result, void* user_data); - void (*alloc_image)(sg_image result, void* user_data); - void (*alloc_sampler)(sg_sampler result, void* user_data); - void (*alloc_shader)(sg_shader result, void* user_data); - void (*alloc_pipeline)(sg_pipeline result, void* user_data); - void (*alloc_attachments)(sg_attachments result, void* user_data); - void (*dealloc_buffer)(sg_buffer buf_id, void* user_data); - void (*dealloc_image)(sg_image img_id, void* user_data); - void (*dealloc_sampler)(sg_sampler smp_id, void* user_data); - void (*dealloc_shader)(sg_shader shd_id, void* user_data); - void (*dealloc_pipeline)(sg_pipeline pip_id, void* user_data); - void (*dealloc_attachments)(sg_attachments atts_id, void* user_data); - void (*init_buffer)(sg_buffer buf_id, const sg_buffer_desc* desc, void* user_data); - void (*init_image)(sg_image img_id, const sg_image_desc* desc, void* user_data); - void (*init_sampler)(sg_sampler smp_id, const sg_sampler_desc* desc, void* user_data); - void (*init_shader)(sg_shader shd_id, const sg_shader_desc* desc, void* user_data); - void (*init_pipeline)(sg_pipeline pip_id, const sg_pipeline_desc* desc, void* user_data); - void (*init_attachments)(sg_attachments atts_id, const sg_attachments_desc* desc, void* user_data); - void (*uninit_buffer)(sg_buffer buf_id, void* user_data); - void (*uninit_image)(sg_image img_id, void* user_data); - void (*uninit_sampler)(sg_sampler smp_id, void* user_data); - void (*uninit_shader)(sg_shader shd_id, void* user_data); - void (*uninit_pipeline)(sg_pipeline pip_id, void* user_data); - void (*uninit_attachments)(sg_attachments atts_id, void* user_data); - void (*fail_buffer)(sg_buffer buf_id, void* user_data); - void (*fail_image)(sg_image img_id, void* user_data); - void (*fail_sampler)(sg_sampler smp_id, void* user_data); - void (*fail_shader)(sg_shader shd_id, void* user_data); - void (*fail_pipeline)(sg_pipeline pip_id, void* user_data); - void (*fail_attachments)(sg_attachments atts_id, void* user_data); - void (*push_debug_group)(const char* name, void* user_data); - void (*pop_debug_group)(void* user_data); -} sg_trace_hooks; - -/* - sg_buffer_info - sg_image_info - sg_sampler_info - sg_shader_info - sg_pipeline_info - sg_attachments_info - - These structs contain various internal resource attributes which - might be useful for debug-inspection. Please don't rely on the - actual content of those structs too much, as they are quite closely - tied to sokol_gfx.h internals and may change more frequently than - the other public API elements. - - The *_info structs are used as the return values of the following functions: - - sg_query_buffer_info() - sg_query_image_info() - sg_query_sampler_info() - sg_query_shader_info() - sg_query_pipeline_info() - sg_query_pass_info() -*/ -typedef struct sg_slot_info { - sg_resource_state state; // the current state of this resource slot - uint32_t res_id; // type-neutral resource if (e.g. sg_buffer.id) -} sg_slot_info; - -typedef struct sg_buffer_info { - sg_slot_info slot; // resource pool slot info - uint32_t update_frame_index; // frame index of last sg_update_buffer() - uint32_t append_frame_index; // frame index of last sg_append_buffer() - int append_pos; // current position in buffer for sg_append_buffer() - bool append_overflow; // is buffer in overflow state (due to sg_append_buffer) - int num_slots; // number of renaming-slots for dynamically updated buffers - int active_slot; // currently active write-slot for dynamically updated buffers -} sg_buffer_info; - -typedef struct sg_image_info { - sg_slot_info slot; // resource pool slot info - uint32_t upd_frame_index; // frame index of last sg_update_image() - int num_slots; // number of renaming-slots for dynamically updated images - int active_slot; // currently active write-slot for dynamically updated images -} sg_image_info; - -typedef struct sg_sampler_info { - sg_slot_info slot; // resource pool slot info -} sg_sampler_info; - -typedef struct sg_shader_info { - sg_slot_info slot; // resource pool slot info -} sg_shader_info; - -typedef struct sg_pipeline_info { - sg_slot_info slot; // resource pool slot info -} sg_pipeline_info; - -typedef struct sg_attachments_info { - sg_slot_info slot; // resource pool slot info -} sg_attachments_info; - -/* - sg_frame_stats - - Allows to track generic and backend-specific stats about a - render frame. Obtained by calling sg_query_frame_stats(). The returned - struct contains information about the *previous* frame. -*/ -typedef struct sg_frame_stats_gl { - uint32_t num_bind_buffer; - uint32_t num_active_texture; - uint32_t num_bind_texture; - uint32_t num_bind_sampler; - uint32_t num_use_program; - uint32_t num_render_state; - uint32_t num_vertex_attrib_pointer; - uint32_t num_vertex_attrib_divisor; - uint32_t num_enable_vertex_attrib_array; - uint32_t num_disable_vertex_attrib_array; - uint32_t num_uniform; -} sg_frame_stats_gl; - -typedef struct sg_frame_stats_d3d11_pass { - uint32_t num_om_set_render_targets; - uint32_t num_clear_render_target_view; - uint32_t num_clear_depth_stencil_view; - uint32_t num_resolve_subresource; -} sg_frame_stats_d3d11_pass; - -typedef struct sg_frame_stats_d3d11_pipeline { - uint32_t num_rs_set_state; - uint32_t num_om_set_depth_stencil_state; - uint32_t num_om_set_blend_state; - uint32_t num_ia_set_primitive_topology; - uint32_t num_ia_set_input_layout; - uint32_t num_vs_set_shader; - uint32_t num_vs_set_constant_buffers; - uint32_t num_ps_set_shader; - uint32_t num_ps_set_constant_buffers; -} sg_frame_stats_d3d11_pipeline; - -typedef struct sg_frame_stats_d3d11_bindings { - uint32_t num_ia_set_vertex_buffers; - uint32_t num_ia_set_index_buffer; - uint32_t num_vs_set_shader_resources; - uint32_t num_ps_set_shader_resources; - uint32_t num_vs_set_samplers; - uint32_t num_ps_set_samplers; -} sg_frame_stats_d3d11_bindings; - -typedef struct sg_frame_stats_d3d11_uniforms { - uint32_t num_update_subresource; -} sg_frame_stats_d3d11_uniforms; - -typedef struct sg_frame_stats_d3d11_draw { - uint32_t num_draw_indexed_instanced; - uint32_t num_draw_indexed; - uint32_t num_draw_instanced; - uint32_t num_draw; -} sg_frame_stats_d3d11_draw; - -typedef struct sg_frame_stats_d3d11 { - sg_frame_stats_d3d11_pass pass; - sg_frame_stats_d3d11_pipeline pipeline; - sg_frame_stats_d3d11_bindings bindings; - sg_frame_stats_d3d11_uniforms uniforms; - sg_frame_stats_d3d11_draw draw; - uint32_t num_map; - uint32_t num_unmap; -} sg_frame_stats_d3d11; - -typedef struct sg_frame_stats_metal_idpool { - uint32_t num_added; - uint32_t num_released; - uint32_t num_garbage_collected; -} sg_frame_stats_metal_idpool; - -typedef struct sg_frame_stats_metal_pipeline { - uint32_t num_set_blend_color; - uint32_t num_set_cull_mode; - uint32_t num_set_front_facing_winding; - uint32_t num_set_stencil_reference_value; - uint32_t num_set_depth_bias; - uint32_t num_set_render_pipeline_state; - uint32_t num_set_depth_stencil_state; -} sg_frame_stats_metal_pipeline; - -typedef struct sg_frame_stats_metal_bindings { - uint32_t num_set_vertex_buffer; - uint32_t num_set_vertex_texture; - uint32_t num_set_vertex_sampler_state; - uint32_t num_set_fragment_buffer; - uint32_t num_set_fragment_texture; - uint32_t num_set_fragment_sampler_state; -} sg_frame_stats_metal_bindings; - -typedef struct sg_frame_stats_metal_uniforms { - uint32_t num_set_vertex_buffer_offset; - uint32_t num_set_fragment_buffer_offset; -} sg_frame_stats_metal_uniforms; - -typedef struct sg_frame_stats_metal { - sg_frame_stats_metal_idpool idpool; - sg_frame_stats_metal_pipeline pipeline; - sg_frame_stats_metal_bindings bindings; - sg_frame_stats_metal_uniforms uniforms; -} sg_frame_stats_metal; - -typedef struct sg_frame_stats_wgpu_uniforms { - uint32_t num_set_bindgroup; - uint32_t size_write_buffer; -} sg_frame_stats_wgpu_uniforms; - -typedef struct sg_frame_stats_wgpu_bindings { - uint32_t num_set_vertex_buffer; - uint32_t num_skip_redundant_vertex_buffer; - uint32_t num_set_index_buffer; - uint32_t num_skip_redundant_index_buffer; - uint32_t num_create_bindgroup; - uint32_t num_discard_bindgroup; - uint32_t num_set_bindgroup; - uint32_t num_skip_redundant_bindgroup; - uint32_t num_bindgroup_cache_hits; - uint32_t num_bindgroup_cache_misses; - uint32_t num_bindgroup_cache_collisions; - uint32_t num_bindgroup_cache_invalidates; - uint32_t num_bindgroup_cache_hash_vs_key_mismatch; -} sg_frame_stats_wgpu_bindings; - -typedef struct sg_frame_stats_wgpu { - sg_frame_stats_wgpu_uniforms uniforms; - sg_frame_stats_wgpu_bindings bindings; -} sg_frame_stats_wgpu; - -typedef struct sg_frame_stats { - uint32_t frame_index; // current frame counter, starts at 0 - - uint32_t num_passes; - uint32_t num_apply_viewport; - uint32_t num_apply_scissor_rect; - uint32_t num_apply_pipeline; - uint32_t num_apply_bindings; - uint32_t num_apply_uniforms; - uint32_t num_draw; - uint32_t num_update_buffer; - uint32_t num_append_buffer; - uint32_t num_update_image; - - uint32_t size_apply_uniforms; - uint32_t size_update_buffer; - uint32_t size_append_buffer; - uint32_t size_update_image; - - uint32_t num_tris; - uint32_t num_verts; - - sg_frame_stats_gl gl; - sg_frame_stats_d3d11 d3d11; - sg_frame_stats_metal metal; - sg_frame_stats_wgpu wgpu; -} sg_frame_stats; - -/* - sg_log_item - - An enum with a unique item for each log message, warning, error - and validation layer message. -*/ -#define _SG_LOG_ITEMS \ - _SG_LOGITEM_XMACRO(OK, "Ok") \ - _SG_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SG_LOGITEM_XMACRO(GL_TEXTURE_FORMAT_NOT_SUPPORTED, "pixel format not supported for texture (gl)") \ - _SG_LOGITEM_XMACRO(GL_3D_TEXTURES_NOT_SUPPORTED, "3d textures not supported (gl)") \ - _SG_LOGITEM_XMACRO(GL_ARRAY_TEXTURES_NOT_SUPPORTED, "array textures not supported (gl)") \ - _SG_LOGITEM_XMACRO(GL_SHADER_COMPILATION_FAILED, "shader compilation failed (gl)") \ - _SG_LOGITEM_XMACRO(GL_SHADER_LINKING_FAILED, "shader linking failed (gl)") \ - _SG_LOGITEM_XMACRO(GL_VERTEX_ATTRIBUTE_NOT_FOUND_IN_SHADER, "vertex attribute not found in shader (gl)") \ - _SG_LOGITEM_XMACRO(GL_TEXTURE_NAME_NOT_FOUND_IN_SHADER, "texture name not found in shader (gl)") \ - _SG_LOGITEM_XMACRO(GL_FRAMEBUFFER_STATUS_UNDEFINED, "framebuffer completeness check failed with GL_FRAMEBUFFER_UNDEFINED (gl)") \ - _SG_LOGITEM_XMACRO(GL_FRAMEBUFFER_STATUS_INCOMPLETE_ATTACHMENT, "framebuffer completeness check failed with GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (gl)") \ - _SG_LOGITEM_XMACRO(GL_FRAMEBUFFER_STATUS_INCOMPLETE_MISSING_ATTACHMENT, "framebuffer completeness check failed with GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (gl)") \ - _SG_LOGITEM_XMACRO(GL_FRAMEBUFFER_STATUS_UNSUPPORTED, "framebuffer completeness check failed with GL_FRAMEBUFFER_UNSUPPORTED (gl)") \ - _SG_LOGITEM_XMACRO(GL_FRAMEBUFFER_STATUS_INCOMPLETE_MULTISAMPLE, "framebuffer completeness check failed with GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE (gl)") \ - _SG_LOGITEM_XMACRO(GL_FRAMEBUFFER_STATUS_UNKNOWN, "framebuffer completeness check failed (unknown reason) (gl)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_BUFFER_FAILED, "CreateBuffer() failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_BUFFER_SRV_FAILED, "CreateShaderResourceView() failed for storage buffer (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_DEPTH_TEXTURE_UNSUPPORTED_PIXEL_FORMAT, "pixel format not supported for depth-stencil texture (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_DEPTH_TEXTURE_FAILED, "CreateTexture2D() failed for depth-stencil texture (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_2D_TEXTURE_UNSUPPORTED_PIXEL_FORMAT, "pixel format not supported for 2d-, cube- or array-texture (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_2D_TEXTURE_FAILED, "CreateTexture2D() failed for 2d-, cube- or array-texture (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_2D_SRV_FAILED, "CreateShaderResourceView() failed for 2d-, cube- or array-texture (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_3D_TEXTURE_UNSUPPORTED_PIXEL_FORMAT, "pixel format not supported for 3D texture (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_3D_TEXTURE_FAILED, "CreateTexture3D() failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_3D_SRV_FAILED, "CreateShaderResourceView() failed for 3d texture (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_MSAA_TEXTURE_FAILED, "CreateTexture2D() failed for MSAA render target texture (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_SAMPLER_STATE_FAILED, "CreateSamplerState() failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_LOAD_D3DCOMPILER_47_DLL_FAILED, "loading d3dcompiler_47.dll failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_SHADER_COMPILATION_FAILED, "shader compilation failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_SHADER_COMPILATION_OUTPUT, "") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_CONSTANT_BUFFER_FAILED, "CreateBuffer() failed for uniform constant buffer (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_INPUT_LAYOUT_FAILED, "CreateInputLayout() failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_RASTERIZER_STATE_FAILED, "CreateRasterizerState() failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_DEPTH_STENCIL_STATE_FAILED, "CreateDepthStencilState() failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_BLEND_STATE_FAILED, "CreateBlendState() failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_RTV_FAILED, "CreateRenderTargetView() failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_CREATE_DSV_FAILED, "CreateDepthStencilView() failed (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_MAP_FOR_UPDATE_BUFFER_FAILED, "Map() failed when updating buffer (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_MAP_FOR_APPEND_BUFFER_FAILED, "Map() failed when appending to buffer (d3d11)") \ - _SG_LOGITEM_XMACRO(D3D11_MAP_FOR_UPDATE_IMAGE_FAILED, "Map() failed when updating image (d3d11)") \ - _SG_LOGITEM_XMACRO(METAL_CREATE_BUFFER_FAILED, "failed to create buffer object (metal)") \ - _SG_LOGITEM_XMACRO(METAL_TEXTURE_FORMAT_NOT_SUPPORTED, "pixel format not supported for texture (metal)") \ - _SG_LOGITEM_XMACRO(METAL_CREATE_TEXTURE_FAILED, "failed to create texture object (metal)") \ - _SG_LOGITEM_XMACRO(METAL_CREATE_SAMPLER_FAILED, "failed to create sampler object (metal)") \ - _SG_LOGITEM_XMACRO(METAL_SHADER_COMPILATION_FAILED, "shader compilation failed (metal)") \ - _SG_LOGITEM_XMACRO(METAL_SHADER_CREATION_FAILED, "shader creation failed (metal)") \ - _SG_LOGITEM_XMACRO(METAL_SHADER_COMPILATION_OUTPUT, "") \ - _SG_LOGITEM_XMACRO(METAL_VERTEX_SHADER_ENTRY_NOT_FOUND, "vertex shader entry function not found (metal)") \ - _SG_LOGITEM_XMACRO(METAL_FRAGMENT_SHADER_ENTRY_NOT_FOUND, "fragment shader entry not found (metal)") \ - _SG_LOGITEM_XMACRO(METAL_CREATE_RPS_FAILED, "failed to create render pipeline state (metal)") \ - _SG_LOGITEM_XMACRO(METAL_CREATE_RPS_OUTPUT, "") \ - _SG_LOGITEM_XMACRO(METAL_CREATE_DSS_FAILED, "failed to create depth stencil state (metal)") \ - _SG_LOGITEM_XMACRO(WGPU_BINDGROUPS_POOL_EXHAUSTED, "bindgroups pool exhausted (increase sg_desc.bindgroups_cache_size) (wgpu)") \ - _SG_LOGITEM_XMACRO(WGPU_BINDGROUPSCACHE_SIZE_GREATER_ONE, "sg_desc.wgpu_bindgroups_cache_size must be > 1 (wgpu)") \ - _SG_LOGITEM_XMACRO(WGPU_BINDGROUPSCACHE_SIZE_POW2, "sg_desc.wgpu_bindgroups_cache_size must be a power of 2 (wgpu)") \ - _SG_LOGITEM_XMACRO(WGPU_CREATEBINDGROUP_FAILED, "wgpuDeviceCreateBindGroup failed") \ - _SG_LOGITEM_XMACRO(WGPU_CREATE_BUFFER_FAILED, "wgpuDeviceCreateBuffer() failed") \ - _SG_LOGITEM_XMACRO(WGPU_CREATE_TEXTURE_FAILED, "wgpuDeviceCreateTexture() failed") \ - _SG_LOGITEM_XMACRO(WGPU_CREATE_TEXTURE_VIEW_FAILED, "wgpuTextureCreateView() failed") \ - _SG_LOGITEM_XMACRO(WGPU_CREATE_SAMPLER_FAILED, "wgpuDeviceCreateSampler() failed") \ - _SG_LOGITEM_XMACRO(WGPU_CREATE_SHADER_MODULE_FAILED, "wgpuDeviceCreateShaderModule() failed") \ - _SG_LOGITEM_XMACRO(WGPU_SHADER_TOO_MANY_IMAGES, "shader uses too many sampled images on shader stage (wgpu)") \ - _SG_LOGITEM_XMACRO(WGPU_SHADER_TOO_MANY_SAMPLERS, "shader uses too many samplers on shader stage (wgpu)") \ - _SG_LOGITEM_XMACRO(WGPU_SHADER_TOO_MANY_STORAGEBUFFERS, "shader uses too many storage buffer bindings on shader stage (wgpu)") \ - _SG_LOGITEM_XMACRO(WGPU_SHADER_CREATE_BINDGROUP_LAYOUT_FAILED, "wgpuDeviceCreateBindGroupLayout() for shader stage failed") \ - _SG_LOGITEM_XMACRO(WGPU_CREATE_PIPELINE_LAYOUT_FAILED, "wgpuDeviceCreatePipelineLayout() failed") \ - _SG_LOGITEM_XMACRO(WGPU_CREATE_RENDER_PIPELINE_FAILED, "wgpuDeviceCreateRenderPipeline() failed") \ - _SG_LOGITEM_XMACRO(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED, "wgpuTextureCreateView() failed in create attachments") \ - _SG_LOGITEM_XMACRO(IDENTICAL_COMMIT_LISTENER, "attempting to add identical commit listener") \ - _SG_LOGITEM_XMACRO(COMMIT_LISTENER_ARRAY_FULL, "commit listener array full") \ - _SG_LOGITEM_XMACRO(TRACE_HOOKS_NOT_ENABLED, "sg_install_trace_hooks() called, but SOKOL_TRACE_HOOKS is not defined") \ - _SG_LOGITEM_XMACRO(DEALLOC_BUFFER_INVALID_STATE, "sg_dealloc_buffer(): buffer must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(DEALLOC_IMAGE_INVALID_STATE, "sg_dealloc_image(): image must be in alloc state") \ - _SG_LOGITEM_XMACRO(DEALLOC_SAMPLER_INVALID_STATE, "sg_dealloc_sampler(): sampler must be in alloc state") \ - _SG_LOGITEM_XMACRO(DEALLOC_SHADER_INVALID_STATE, "sg_dealloc_shader(): shader must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(DEALLOC_PIPELINE_INVALID_STATE, "sg_dealloc_pipeline(): pipeline must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(DEALLOC_ATTACHMENTS_INVALID_STATE, "sg_dealloc_attachments(): attachments must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(INIT_BUFFER_INVALID_STATE, "sg_init_buffer(): buffer must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(INIT_IMAGE_INVALID_STATE, "sg_init_image(): image must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(INIT_SAMPLER_INVALID_STATE, "sg_init_sampler(): sampler must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(INIT_SHADER_INVALID_STATE, "sg_init_shader(): shader must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(INIT_PIPELINE_INVALID_STATE, "sg_init_pipeline(): pipeline must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(INIT_ATTACHMENTS_INVALID_STATE, "sg_init_attachments(): pass must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(UNINIT_BUFFER_INVALID_STATE, "sg_uninit_buffer(): buffer must be in VALID or FAILED state") \ - _SG_LOGITEM_XMACRO(UNINIT_IMAGE_INVALID_STATE, "sg_uninit_image(): image must be in VALID or FAILED state") \ - _SG_LOGITEM_XMACRO(UNINIT_SAMPLER_INVALID_STATE, "sg_uninit_sampler(): sampler must be in VALID or FAILED state") \ - _SG_LOGITEM_XMACRO(UNINIT_SHADER_INVALID_STATE, "sg_uninit_shader(): shader must be in VALID or FAILED state") \ - _SG_LOGITEM_XMACRO(UNINIT_PIPELINE_INVALID_STATE, "sg_uninit_pipeline(): pipeline must be in VALID or FAILED state") \ - _SG_LOGITEM_XMACRO(UNINIT_ATTACHMENTS_INVALID_STATE, "sg_uninit_attachments(): attachments must be in VALID or FAILED state") \ - _SG_LOGITEM_XMACRO(FAIL_BUFFER_INVALID_STATE, "sg_fail_buffer(): buffer must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(FAIL_IMAGE_INVALID_STATE, "sg_fail_image(): image must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(FAIL_SAMPLER_INVALID_STATE, "sg_fail_sampler(): sampler must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(FAIL_SHADER_INVALID_STATE, "sg_fail_shader(): shader must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(FAIL_PIPELINE_INVALID_STATE, "sg_fail_pipeline(): pipeline must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(FAIL_ATTACHMENTS_INVALID_STATE, "sg_fail_attachments(): attachments must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(BUFFER_POOL_EXHAUSTED, "buffer pool exhausted") \ - _SG_LOGITEM_XMACRO(IMAGE_POOL_EXHAUSTED, "image pool exhausted") \ - _SG_LOGITEM_XMACRO(SAMPLER_POOL_EXHAUSTED, "sampler pool exhausted") \ - _SG_LOGITEM_XMACRO(SHADER_POOL_EXHAUSTED, "shader pool exhausted") \ - _SG_LOGITEM_XMACRO(PIPELINE_POOL_EXHAUSTED, "pipeline pool exhausted") \ - _SG_LOGITEM_XMACRO(PASS_POOL_EXHAUSTED, "pass pool exhausted") \ - _SG_LOGITEM_XMACRO(BEGINPASS_ATTACHMENT_INVALID, "sg_begin_pass: an attachment was provided that no longer exists") \ - _SG_LOGITEM_XMACRO(DRAW_WITHOUT_BINDINGS, "attempting to draw without resource bindings") \ - _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_CANARY, "sg_buffer_desc not initialized") \ - _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_SIZE, "sg_buffer_desc.size and .data.size cannot both be 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_DATA, "immutable buffers must be initialized with data (sg_buffer_desc.data.ptr and sg_buffer_desc.data.size)") \ - _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_DATA_SIZE, "immutable buffer data size differs from buffer size") \ - _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_NO_DATA, "dynamic/stream usage buffers cannot be initialized with data") \ - _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_STORAGEBUFFER_SUPPORTED, "storage buffers not supported by the backend 3D API (requires OpenGL >= 4.3)") \ - _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_STORAGEBUFFER_SIZE_MULTIPLE_4, "size of storage buffers must be a multiple of 4") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDATA_NODATA, "sg_image_data: no data (.ptr and/or .size is zero)") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDATA_DATA_SIZE, "sg_image_data: data size doesn't match expected surface size") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_CANARY, "sg_image_desc not initialized") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_WIDTH, "sg_image_desc.width must be > 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_HEIGHT, "sg_image_desc.height must be > 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_RT_PIXELFORMAT, "invalid pixel format for render-target image") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_NONRT_PIXELFORMAT, "invalid pixel format for non-render-target image") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT, "non-render-target images cannot be multisampled") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT, "MSAA not supported for this pixel format") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_MSAA_NUM_MIPMAPS, "MSAA images must have num_mipmaps == 1") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_MSAA_3D_IMAGE, "3D images cannot have a sample_count > 1") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_DEPTH_3D_IMAGE, "3D images cannot have a depth/stencil image format") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_RT_IMMUTABLE, "render target images must be SG_USAGE_IMMUTABLE") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_RT_NO_DATA, "render target images cannot be initialized with data") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_INJECTED_NO_DATA, "images with injected textures cannot be initialized with data") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA, "dynamic/stream images cannot be initialized with data") \ - _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE, "compressed images must be immutable") \ - _SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_CANARY, "sg_sampler_desc not initialized") \ - _SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_ANISTROPIC_REQUIRES_LINEAR_FILTERING, "sg_sampler_desc.max_anisotropy > 1 requires min/mag/mipmap_filter to be SG_FILTER_LINEAR") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_CANARY, "sg_shader_desc not initialized") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SOURCE, "shader source code required") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_BYTECODE, "shader byte code required") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE, "shader source or byte code required") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_BYTECODE_SIZE, "shader byte code length (in bytes) required") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_UBS, "shader uniform blocks must occupy continuous slots") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_UB_MEMBERS, "uniform block members must occupy continuous slots") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_UB_MEMBERS, "GL backend requires uniform block member declarations") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_MEMBER_NAME, "uniform block member name missing") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_SIZE_MISMATCH, "size of uniform block members doesn't match uniform block size") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_ARRAY_COUNT, "uniform array count must be >= 1") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE, "uniform arrays only allowed for FLOAT4, INT4, MAT4 in std140 layout") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_STORAGEBUFFERS, "shader stage storage buffers must occupy continuous slots (sg_shader_desc.vs|fs.storage_buffers[])") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_STORAGEBUFFER_READONLY, "shader stage storage buffers must be readonly (sg_shader_desc.vs|fs.storage_buffers[].readonly)") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_IMAGES, "shader stage images must occupy continuous slots (sg_shader_desc.vs|fs.images[])") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_SAMPLERS, "shader stage samplers must occupy continuous slots (sg_shader_desc.vs|fs.samplers[])") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_IMAGE_SLOT_OUT_OF_RANGE, "shader stage: image-sampler-pair image slot index is out of range (sg_shader_desc.vs|fs.image_sampler_pairs[].image_slot)") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_SAMPLER_SLOT_OUT_OF_RANGE, "shader stage: image-sampler-pair image slot index is out of range (sg_shader_desc.vs|fs.image_sampler_pairs[].sampler_slot)") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_NAME_REQUIRED_FOR_GL, "shader stage: image-sampler-pairs must be named in GL (sg_shader_desc.vs|fs.image_sampler_pairs[].name)") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_HAS_NAME_BUT_NOT_USED, "shader stage: image-sampler-pair has name but .used field not true") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_HAS_IMAGE_BUT_NOT_USED, "shader stage: image-sampler-pair has .image_slot != 0 but .used field not true") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_HAS_SAMPLER_BUT_NOT_USED, "shader stage: image-sampler-pair .sampler_slot != 0 but .used field not true") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NONFILTERING_SAMPLER_REQUIRED, "shader stage: image sample type UNFILTERABLE_FLOAT, UINT, SINT can only be used with NONFILTERING sampler") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_COMPARISON_SAMPLER_REQUIRED, "shader stage: image sample type DEPTH can only be used with COMPARISON sampler") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMAGE_NOT_REFERENCED_BY_IMAGE_SAMPLER_PAIRS, "shader stage: one or more images are note referenced by (sg_shader_desc.vs|fs.image_sampler_pairs[].image_slot)") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SAMPLER_NOT_REFERENCED_BY_IMAGE_SAMPLER_PAIRS, "shader stage: one or more samplers are not referenced by image-sampler-pairs (sg_shader_desc.vs|fs.image_sampler_pairs[].sampler_slot)") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_IMAGE_SAMPLER_PAIRS, "shader stage image-sampler-pairs must occupy continuous slots (sg_shader_desc.vs|fs.image_samplers[])") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG, "vertex attribute name/semantic string too long (max len 16)") \ - _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_CANARY, "sg_pipeline_desc not initialized") \ - _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_SHADER, "sg_pipeline_desc.shader missing or invalid") \ - _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_NO_CONT_ATTRS, "sg_pipeline_desc.layout.attrs is not continuous") \ - _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4, "sg_pipeline_desc.layout.buffers[].stride must be multiple of 4") \ - _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_ATTR_SEMANTICS, "D3D11 missing vertex attribute semantics in shader") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_CANARY, "sg_attachments_desc not initialized") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_NO_ATTACHMENTS, "sg_attachments_desc no color or depth-stencil attachments") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_NO_CONT_COLOR_ATTS, "color attachments must occupy continuous slots") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_IMAGE, "pass attachment image is not valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_MIPLEVEL, "pass attachment mip level is bigger than image has mipmaps") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_FACE, "pass attachment image is cubemap, but face index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_LAYER, "pass attachment image is array texture, but layer index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_SLICE, "pass attachment image is 3d texture, but slice value is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_IMAGE_NO_RT, "pass attachment image must be have render_target=true") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_COLOR_INV_PIXELFORMAT, "pass color-attachment images must be renderable color pixel format") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_INV_PIXELFORMAT, "pass depth-attachment image must be depth or depth-stencil pixel format") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_IMAGE_SIZES, "all pass attachments must have the same size") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_IMAGE_SAMPLE_COUNTS, "all pass attachments must have the same sample count") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_COLOR_IMAGE_MSAA, "pass resolve attachments must have a color attachment image with sample count > 1") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE, "pass resolve attachment image not valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_SAMPLE_COUNT, "pass resolve attachment image sample count must be 1") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_MIPLEVEL, "pass resolve attachment mip level is bigger than image has mipmaps") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_FACE, "pass resolve attachment is cubemap, but face index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_LAYER, "pass resolve attachment is array texture, but layer index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_SLICE, "pass resolve attachment is 3d texture, but slice value is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_NO_RT, "pass resolve attachment image must have render_target=true") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES, "pass resolve attachment size must match color attachment image size") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_FORMAT, "pass resolve attachment pixel format must match color attachment pixel format") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE, "pass depth attachment image is not valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_MIPLEVEL, "pass depth attachment mip level is bigger than image has mipmaps") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_FACE, "pass depth attachment image is cubemap, but face index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_LAYER, "pass depth attachment image is array texture, but layer index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_SLICE, "pass depth attachment image is 3d texture, but slice value is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_NO_RT, "pass depth attachment image must be have render_target=true") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES, "pass depth attachment image size must match color attachment image size") \ - _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SAMPLE_COUNT, "pass depth attachment sample count must match color attachment sample count") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_CANARY, "sg_begin_pass: pass struct not initialized") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_ATTACHMENTS_EXISTS, "sg_begin_pass: attachments object no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_ATTACHMENTS_VALID, "sg_begin_pass: attachments object not in resource state VALID") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE, "sg_begin_pass: one or more color attachment images are not valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE, "sg_begin_pass: one or more resolve attachment images are not valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE, "sg_begin_pass: one or more depth-stencil attachment images are not valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH, "sg_begin_pass: expected pass.swapchain.width > 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH_NOTSET, "sg_begin_pass: expected pass.swapchain.width == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_HEIGHT, "sg_begin_pass: expected pass.swapchain.height > 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_HEIGHT_NOTSET, "sg_begin_pass: expected pass.swapchain.height == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_SAMPLECOUNT, "sg_begin_pass: expected pass.swapchain.sample_count > 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_SAMPLECOUNT_NOTSET, "sg_begin_pass: expected pass.swapchain.sample_count == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_COLORFORMAT, "sg_begin_pass: expected pass.swapchain.color_format to be valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_COLORFORMAT_NOTSET, "sg_begin_pass: expected pass.swapchain.color_format to be unset") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_DEPTHFORMAT_NOTSET, "sg_begin_pass: expected pass.swapchain.depth_format to be unset") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_CURRENTDRAWABLE, "sg_begin_pass: expected pass.swapchain.metal.current_drawable != 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_CURRENTDRAWABLE_NOTSET, "sg_begin_pass: expected pass.swapchain.metal.current_drawable == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE, "sg_begin_pass: expected pass.swapchain.metal.depth_stencil_texture != 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE_NOTSET, "sg_begin_pass: expected pass.swapchain.metal.depth_stencil_texture == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE, "sg_begin_pass: expected pass.swapchain.metal.msaa_color_texture != 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE_NOTSET, "sg_begin_pass: expected pass.swapchain.metal.msaa_color_texture == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RENDERVIEW, "sg_begin_pass: expected pass.swapchain.d3d11.render_view != 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RENDERVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.d3d11.render_view == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW, "sg_begin_pass: expected pass.swapchain.d3d11.resolve_view != 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.d3d11.resolve_view == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW, "sg_begin_pass: expected pass.swapchain.d3d11.depth_stencil_view != 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.d3d11.depth_stencil_view == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RENDERVIEW, "sg_begin_pass: expected pass.swapchain.wgpu.render_view != 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RENDERVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.wgpu.render_view == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW, "sg_begin_pass: expected pass.swapchain.wgpu.resolve_view != 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.wgpu.resolve_view == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW, "sg_begin_pass: expected pass.swapchain.wgpu.depth_stencil_view != 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.wgpu.depth_stencil_view == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_GL_EXPECT_FRAMEBUFFER_NOTSET, "sg_begin_pass: expected pass.swapchain.gl.framebuffer == 0") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_VALID_ID, "sg_apply_pipeline: invalid pipeline id provided") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_EXISTS, "sg_apply_pipeline: pipeline object no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_VALID, "sg_apply_pipeline: pipeline object not in valid state") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_SHADER_EXISTS, "sg_apply_pipeline: shader object no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_SHADER_VALID, "sg_apply_pipeline: shader object not in valid state") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_CURPASS_ATTACHMENTS_EXISTS, "sg_apply_pipeline: current pass attachments no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_CURPASS_ATTACHMENTS_VALID, "sg_apply_pipeline: current pass attachments not in valid state") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_ATT_COUNT, "sg_apply_pipeline: number of pipeline color attachments doesn't match number of pass color attachments") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_COLOR_FORMAT, "sg_apply_pipeline: pipeline color attachment pixel format doesn't match pass color attachment pixel format") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_DEPTH_FORMAT, "sg_apply_pipeline: pipeline depth pixel_format doesn't match pass depth attachment pixel format") \ - _SG_LOGITEM_XMACRO(VALIDATE_APIP_SAMPLE_COUNT, "sg_apply_pipeline: pipeline MSAA sample count doesn't match render pass attachment sample count") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_PIPELINE, "sg_apply_bindings: must be called after sg_apply_pipeline") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_PIPELINE_EXISTS, "sg_apply_bindings: currently applied pipeline object no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_PIPELINE_VALID, "sg_apply_bindings: currently applied pipeline object not in valid state") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VBS, "sg_apply_bindings: number of vertex buffers doesn't match number of pipeline vertex layouts") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VB_EXISTS, "sg_apply_bindings: vertex buffer no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VB_TYPE, "sg_apply_bindings: buffer in vertex buffer slot is not a SG_BUFFERTYPE_VERTEXBUFFER") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VB_OVERFLOW, "sg_apply_bindings: buffer in vertex buffer slot is overflown") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_NO_IB, "sg_apply_bindings: pipeline object defines indexed rendering, but no index buffer provided") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_IB, "sg_apply_bindings: pipeline object defines non-indexed rendering, but index buffer provided") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_IB_EXISTS, "sg_apply_bindings: index buffer no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_IB_TYPE, "sg_apply_bindings: buffer in index buffer slot is not a SG_BUFFERTYPE_INDEXBUFFER") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_IB_OVERFLOW, "sg_apply_bindings: buffer in index buffer slot is overflown") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_EXPECTED_IMAGE_BINDING, "sg_apply_bindings: image binding on vertex stage is missing or the image handle is invalid") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_IMG_EXISTS, "sg_apply_bindings: image bound to vertex stage no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_IMAGE_TYPE_MISMATCH, "sg_apply_bindings: type of image bound to vertex stage doesn't match shader desc") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_IMAGE_MSAA, "sg_apply_bindings: cannot bind image with sample_count>1 to vertex stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_EXPECTED_FILTERABLE_IMAGE, "sg_apply_bindings: filterable image expected on vertex stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_EXPECTED_DEPTH_IMAGE, "sg_apply_bindings: depth image expected on vertex stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_UNEXPECTED_IMAGE_BINDING, "sg_apply_bindings: unexpected image binding on vertex stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_EXPECTED_SAMPLER_BINDING, "sg_apply_bindings: sampler binding on vertex stage is missing or the sampler handle is invalid") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_UNEXPECTED_SAMPLER_COMPARE_NEVER, "sg_apply_bindings: shader expects SG_SAMPLERTYPE_COMPARISON on vertex stage but sampler has SG_COMPAREFUNC_NEVER") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_EXPECTED_SAMPLER_COMPARE_NEVER, "sg_apply_bindings: shader expects SG_SAMPLERTYPE_FILTERING or SG_SAMPLERTYPE_NONFILTERING on vertex stage but sampler doesn't have SG_COMPAREFUNC_NEVER") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_EXPECTED_NONFILTERING_SAMPLER, "sg_apply_bindings: shader expected SG_SAMPLERTYPE_NONFILTERING on vertex stage, but sampler has SG_FILTER_LINEAR filters") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_UNEXPECTED_SAMPLER_BINDING, "sg_apply_bindings: unexpected sampler binding on vertex stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_SMP_EXISTS, "sg_apply_bindings: sampler bound to vertex stage no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_EXPECTED_STORAGEBUFFER_BINDING, "sg_apply_bindings: storage buffer binding on vertex stage is missing or the buffer handle is invalid") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_STORAGEBUFFER_EXISTS, "sg_apply_bindings: storage buffer bound to vertex stage no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_STORAGEBUFFER_BINDING_BUFFERTYPE, "sg_apply_bindings: buffer bound to vertex stage storage buffer slot is not of type storage buffer") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_UNEXPECTED_STORAGEBUFFER_BINDING, "sg_apply_bindings: unexpected storage buffer binding on vertex stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_IMAGE_BINDING, "sg_apply_bindings: image binding on fragment stage is missing or the image handle is invalid") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_IMG_EXISTS, "sg_apply_bindings: image bound to fragment stage no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_IMAGE_TYPE_MISMATCH, "sg_apply_bindings: type of image bound to fragment stage doesn't match shader desc") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_IMAGE_MSAA, "sg_apply_bindings: cannot bind image with sample_count>1 to fragment stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_FILTERABLE_IMAGE, "sg_apply_bindings: filterable image expected on fragment stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_DEPTH_IMAGE, "sg_apply_bindings: depth image expected on fragment stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_UNEXPECTED_IMAGE_BINDING, "sg_apply_bindings: unexpected image binding on fragment stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_SAMPLER_BINDING, "sg_apply_bindings: sampler binding on fragment stage is missing or the sampler handle is invalid") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_UNEXPECTED_SAMPLER_COMPARE_NEVER, "sg_apply_bindings: shader expects SG_SAMPLERTYPE_COMPARISON on fragment stage but sampler has SG_COMPAREFUNC_NEVER") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_SAMPLER_COMPARE_NEVER, "sg_apply_bindings: shader expects SG_SAMPLERTYPE_FILTERING on fragment stage but sampler doesn't have SG_COMPAREFUNC_NEVER") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_NONFILTERING_SAMPLER, "sg_apply_bindings: shader expected SG_SAMPLERTYPE_NONFILTERING on fragment stage, but sampler has SG_FILTER_LINEAR filters") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_UNEXPECTED_SAMPLER_BINDING, "sg_apply_bindings: unexpected sampler binding on fragment stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_SMP_EXISTS, "sg_apply_bindings: sampler bound to fragment stage no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_STORAGEBUFFER_BINDING, "sg_apply_bindings: storage buffer binding on fragment stage is missing or the buffer handle is invalid") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_STORAGEBUFFER_EXISTS, "sg_apply_bindings: storage buffer bound to fragment stage no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_STORAGEBUFFER_BINDING_BUFFERTYPE, "sg_apply_bindings: buffer bound to frahment stage storage buffer slot is not of type storage buffer") \ - _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_UNEXPECTED_STORAGEBUFFER_BINDING, "sg_apply_bindings: unexpected storage buffer binding on fragment stage") \ - _SG_LOGITEM_XMACRO(VALIDATE_AUB_NO_PIPELINE, "sg_apply_uniforms: must be called after sg_apply_pipeline()") \ - _SG_LOGITEM_XMACRO(VALIDATE_AUB_NO_UB_AT_SLOT, "sg_apply_uniforms: no uniform block declaration at this shader stage UB slot") \ - _SG_LOGITEM_XMACRO(VALIDATE_AUB_SIZE, "sg_apply_uniforms: data size doesn't match declared uniform block size") \ - _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_USAGE, "sg_update_buffer: cannot update immutable buffer") \ - _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_SIZE, "sg_update_buffer: update size is bigger than buffer size") \ - _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_ONCE, "sg_update_buffer: only one update allowed per buffer and frame") \ - _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_APPEND, "sg_update_buffer: cannot call sg_update_buffer and sg_append_buffer in same frame") \ - _SG_LOGITEM_XMACRO(VALIDATE_APPENDBUF_USAGE, "sg_append_buffer: cannot append to immutable buffer") \ - _SG_LOGITEM_XMACRO(VALIDATE_APPENDBUF_SIZE, "sg_append_buffer: overall appended size is bigger than buffer size") \ - _SG_LOGITEM_XMACRO(VALIDATE_APPENDBUF_UPDATE, "sg_append_buffer: cannot call sg_append_buffer and sg_update_buffer in same frame") \ - _SG_LOGITEM_XMACRO(VALIDATE_UPDIMG_USAGE, "sg_update_image: cannot update immutable image") \ - _SG_LOGITEM_XMACRO(VALIDATE_UPDIMG_ONCE, "sg_update_image: only one update allowed per image and frame") \ - _SG_LOGITEM_XMACRO(VALIDATION_FAILED, "validation layer checks failed") \ - -#define _SG_LOGITEM_XMACRO(item,msg) SG_LOGITEM_##item, -typedef enum sg_log_item { - _SG_LOG_ITEMS -} sg_log_item; -#undef _SG_LOGITEM_XMACRO - -/* - sg_desc - - The sg_desc struct contains configuration values for sokol_gfx, - it is used as parameter to the sg_setup() call. - - The default configuration is: - - .buffer_pool_size 128 - .image_pool_size 128 - .sampler_pool_size 64 - .shader_pool_size 32 - .pipeline_pool_size 64 - .pass_pool_size 16 - .uniform_buffer_size 4 MB (4*1024*1024) - .max_commit_listeners 1024 - .disable_validation false - .mtl_force_managed_storage_mode false - .wgpu_disable_bindgroups_cache false - .wgpu_bindgroups_cache_size 1024 - - .allocator.alloc_fn 0 (in this case, malloc() will be called) - .allocator.free_fn 0 (in this case, free() will be called) - .allocator.user_data 0 - - .environment.defaults.color_format: default value depends on selected backend: - all GL backends: SG_PIXELFORMAT_RGBA8 - Metal and D3D11: SG_PIXELFORMAT_BGRA8 - WebGPU: *no default* (must be queried from WebGPU swapchain object) - .environment.defaults.depth_format: SG_PIXELFORMAT_DEPTH_STENCIL - .environment.defaults.sample_count: 1 - - Metal specific: - (NOTE: All Objective-C object references are transferred through - a bridged (const void*) to sokol_gfx, which will use a unretained - bridged cast (__bridged id) to retrieve the Objective-C - references back. Since the bridge cast is unretained, the caller - must hold a strong reference to the Objective-C object for the - duration of the sokol_gfx call! - - .mtl_force_managed_storage_mode - when enabled, Metal buffers and texture resources are created in managed storage - mode, otherwise sokol-gfx will decide whether to create buffers and - textures in managed or shared storage mode (this is mainly a debugging option) - .mtl_use_command_buffer_with_retained_references - when true, the sokol-gfx Metal backend will use Metal command buffers which - bump the reference count of resource objects as long as they are inflight, - this is slower than the default command-buffer-with-unretained-references - method, this may be a workaround when confronted with lifetime validation - errors from the Metal validation layer until a proper fix has been implemented - .environment.metal.device - a pointer to the MTLDevice object - - D3D11 specific: - .environment.d3d11.device - a pointer to the ID3D11Device object, this must have been created - before sg_setup() is called - .environment.d3d11.device_context - a pointer to the ID3D11DeviceContext object - .d3d11_shader_debugging - set this to true to compile shaders which are provided as HLSL source - code with debug information and without optimization, this allows - shader debugging in tools like RenderDoc, to output source code - instead of byte code from sokol-shdc, omit the `--binary` cmdline - option - - WebGPU specific: - .wgpu_disable_bindgroups_cache - When this is true, the WebGPU backend will create and immediately - release a BindGroup object in the sg_apply_bindings() call, only - use this for debugging purposes. - .wgpu_bindgroups_cache_size - The size of the bindgroups cache for re-using BindGroup objects - between sg_apply_bindings() calls. The smaller the cache size, - the more likely are cache slot collisions which will cause - a BindGroups object to be destroyed and a new one created. - Use the information returned by sg_query_stats() to check - if this is a frequent occurrence, and increase the cache size as - needed (the default is 1024). - NOTE: wgpu_bindgroups_cache_size must be a power-of-2 number! - .environment.wgpu.device - a WGPUDevice handle - - When using sokol_gfx.h and sokol_app.h together, consider using the - helper function sglue_environment() in the sokol_glue.h header to - initialize the sg_desc.environment nested struct. sglue_environment() returns - a completely initialized sg_environment struct with information - provided by sokol_app.h. -*/ -typedef struct sg_environment_defaults { - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; -} sg_environment_defaults; - -typedef struct sg_metal_environment { - const void* device; -} sg_metal_environment; - -typedef struct sg_d3d11_environment { - const void* device; - const void* device_context; -} sg_d3d11_environment; - -typedef struct sg_wgpu_environment { - const void* device; -} sg_wgpu_environment; - -typedef struct sg_environment { - sg_environment_defaults defaults; - sg_metal_environment metal; - sg_d3d11_environment d3d11; - sg_wgpu_environment wgpu; -} sg_environment; - -/* - sg_commit_listener - - Used with function sg_add_commit_listener() to add a callback - which will be called in sg_commit(). This is useful for libraries - building on top of sokol-gfx to be notified about when a frame - ends (instead of having to guess, or add a manual 'new-frame' - function. -*/ -typedef struct sg_commit_listener { - void (*func)(void* user_data); - void* user_data; -} sg_commit_listener; - -/* - sg_allocator - - Used in sg_desc to provide custom memory-alloc and -free functions - to sokol_gfx.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct sg_allocator { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sg_allocator; - -/* - sg_logger - - Used in sg_desc to provide a logging function. Please be aware - that without logging function, sokol-gfx will be completely - silent, e.g. it will not report errors, warnings and - validation layer messages. For maximum error verbosity, - compile in debug mode (e.g. NDEBUG *not* defined) and provide a - compatible logger function in the sg_setup() call - (for instance the standard logging function from sokol_log.h). -*/ -typedef struct sg_logger { - void (*func)( - const char* tag, // always "sg" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SG_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_gfx.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} sg_logger; - -typedef struct sg_desc { - uint32_t _start_canary; - int buffer_pool_size; - int image_pool_size; - int sampler_pool_size; - int shader_pool_size; - int pipeline_pool_size; - int attachments_pool_size; - int uniform_buffer_size; - int max_commit_listeners; - bool disable_validation; // disable validation layer even in debug mode, useful for tests - bool d3d11_shader_debugging; // if true, HLSL shaders are compiled with D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION - bool mtl_force_managed_storage_mode; // for debugging: use Metal managed storage mode for resources even with UMA - bool mtl_use_command_buffer_with_retained_references; // Metal: use a managed MTLCommandBuffer which ref-counts used resources - bool wgpu_disable_bindgroups_cache; // set to true to disable the WebGPU backend BindGroup cache - int wgpu_bindgroups_cache_size; // number of slots in the WebGPU bindgroup cache (must be 2^N) - sg_allocator allocator; - sg_logger logger; // optional log function override - sg_environment environment; - uint32_t _end_canary; -} sg_desc; - -// setup and misc functions -SOKOL_GFX_API_DECL void sg_setup(const sg_desc* desc); -SOKOL_GFX_API_DECL void sg_shutdown(void); -SOKOL_GFX_API_DECL bool sg_isvalid(void); -SOKOL_GFX_API_DECL void sg_reset_state_cache(void); -SOKOL_GFX_API_DECL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace_hooks); -SOKOL_GFX_API_DECL void sg_push_debug_group(const char* name); -SOKOL_GFX_API_DECL void sg_pop_debug_group(void); -SOKOL_GFX_API_DECL bool sg_add_commit_listener(sg_commit_listener listener); -SOKOL_GFX_API_DECL bool sg_remove_commit_listener(sg_commit_listener listener); - -// resource creation, destruction and updating -SOKOL_GFX_API_DECL sg_buffer sg_make_buffer(const sg_buffer_desc* desc); -SOKOL_GFX_API_DECL sg_image sg_make_image(const sg_image_desc* desc); -SOKOL_GFX_API_DECL sg_sampler sg_make_sampler(const sg_sampler_desc* desc); -SOKOL_GFX_API_DECL sg_shader sg_make_shader(const sg_shader_desc* desc); -SOKOL_GFX_API_DECL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc); -SOKOL_GFX_API_DECL sg_attachments sg_make_attachments(const sg_attachments_desc* desc); -SOKOL_GFX_API_DECL void sg_destroy_buffer(sg_buffer buf); -SOKOL_GFX_API_DECL void sg_destroy_image(sg_image img); -SOKOL_GFX_API_DECL void sg_destroy_sampler(sg_sampler smp); -SOKOL_GFX_API_DECL void sg_destroy_shader(sg_shader shd); -SOKOL_GFX_API_DECL void sg_destroy_pipeline(sg_pipeline pip); -SOKOL_GFX_API_DECL void sg_destroy_attachments(sg_attachments atts); -SOKOL_GFX_API_DECL void sg_update_buffer(sg_buffer buf, const sg_range* data); -SOKOL_GFX_API_DECL void sg_update_image(sg_image img, const sg_image_data* data); -SOKOL_GFX_API_DECL int sg_append_buffer(sg_buffer buf, const sg_range* data); -SOKOL_GFX_API_DECL bool sg_query_buffer_overflow(sg_buffer buf); -SOKOL_GFX_API_DECL bool sg_query_buffer_will_overflow(sg_buffer buf, size_t size); - -// rendering functions -SOKOL_GFX_API_DECL void sg_begin_pass(const sg_pass* pass); -SOKOL_GFX_API_DECL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left); -SOKOL_GFX_API_DECL void sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left); -SOKOL_GFX_API_DECL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left); -SOKOL_GFX_API_DECL void sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left); -SOKOL_GFX_API_DECL void sg_apply_pipeline(sg_pipeline pip); -SOKOL_GFX_API_DECL void sg_apply_bindings(const sg_bindings* bindings); -SOKOL_GFX_API_DECL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data); -SOKOL_GFX_API_DECL void sg_draw(int base_element, int num_elements, int num_instances); -SOKOL_GFX_API_DECL void sg_end_pass(void); -SOKOL_GFX_API_DECL void sg_commit(void); - -// getting information -SOKOL_GFX_API_DECL sg_desc sg_query_desc(void); -SOKOL_GFX_API_DECL sg_backend sg_query_backend(void); -SOKOL_GFX_API_DECL sg_features sg_query_features(void); -SOKOL_GFX_API_DECL sg_limits sg_query_limits(void); -SOKOL_GFX_API_DECL sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt); -SOKOL_GFX_API_DECL int sg_query_row_pitch(sg_pixel_format fmt, int width, int row_align_bytes); -SOKOL_GFX_API_DECL int sg_query_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align_bytes); -// get current state of a resource (INITIAL, ALLOC, VALID, FAILED, INVALID) -SOKOL_GFX_API_DECL sg_resource_state sg_query_buffer_state(sg_buffer buf); -SOKOL_GFX_API_DECL sg_resource_state sg_query_image_state(sg_image img); -SOKOL_GFX_API_DECL sg_resource_state sg_query_sampler_state(sg_sampler smp); -SOKOL_GFX_API_DECL sg_resource_state sg_query_shader_state(sg_shader shd); -SOKOL_GFX_API_DECL sg_resource_state sg_query_pipeline_state(sg_pipeline pip); -SOKOL_GFX_API_DECL sg_resource_state sg_query_attachments_state(sg_attachments atts); -// get runtime information about a resource -SOKOL_GFX_API_DECL sg_buffer_info sg_query_buffer_info(sg_buffer buf); -SOKOL_GFX_API_DECL sg_image_info sg_query_image_info(sg_image img); -SOKOL_GFX_API_DECL sg_sampler_info sg_query_sampler_info(sg_sampler smp); -SOKOL_GFX_API_DECL sg_shader_info sg_query_shader_info(sg_shader shd); -SOKOL_GFX_API_DECL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip); -SOKOL_GFX_API_DECL sg_attachments_info sg_query_attachments_info(sg_attachments atts); -// get desc structs matching a specific resource (NOTE that not all creation attributes may be provided) -SOKOL_GFX_API_DECL sg_buffer_desc sg_query_buffer_desc(sg_buffer buf); -SOKOL_GFX_API_DECL sg_image_desc sg_query_image_desc(sg_image img); -SOKOL_GFX_API_DECL sg_sampler_desc sg_query_sampler_desc(sg_sampler smp); -SOKOL_GFX_API_DECL sg_shader_desc sg_query_shader_desc(sg_shader shd); -SOKOL_GFX_API_DECL sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip); -SOKOL_GFX_API_DECL sg_attachments_desc sg_query_attachments_desc(sg_attachments atts); -// get resource creation desc struct with their default values replaced -SOKOL_GFX_API_DECL sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc); -SOKOL_GFX_API_DECL sg_image_desc sg_query_image_defaults(const sg_image_desc* desc); -SOKOL_GFX_API_DECL sg_sampler_desc sg_query_sampler_defaults(const sg_sampler_desc* desc); -SOKOL_GFX_API_DECL sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc); -SOKOL_GFX_API_DECL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc); -SOKOL_GFX_API_DECL sg_attachments_desc sg_query_attachments_defaults(const sg_attachments_desc* desc); - -// separate resource allocation and initialization (for async setup) -SOKOL_GFX_API_DECL sg_buffer sg_alloc_buffer(void); -SOKOL_GFX_API_DECL sg_image sg_alloc_image(void); -SOKOL_GFX_API_DECL sg_sampler sg_alloc_sampler(void); -SOKOL_GFX_API_DECL sg_shader sg_alloc_shader(void); -SOKOL_GFX_API_DECL sg_pipeline sg_alloc_pipeline(void); -SOKOL_GFX_API_DECL sg_attachments sg_alloc_attachments(void); -SOKOL_GFX_API_DECL void sg_dealloc_buffer(sg_buffer buf); -SOKOL_GFX_API_DECL void sg_dealloc_image(sg_image img); -SOKOL_GFX_API_DECL void sg_dealloc_sampler(sg_sampler smp); -SOKOL_GFX_API_DECL void sg_dealloc_shader(sg_shader shd); -SOKOL_GFX_API_DECL void sg_dealloc_pipeline(sg_pipeline pip); -SOKOL_GFX_API_DECL void sg_dealloc_attachments(sg_attachments attachments); -SOKOL_GFX_API_DECL void sg_init_buffer(sg_buffer buf, const sg_buffer_desc* desc); -SOKOL_GFX_API_DECL void sg_init_image(sg_image img, const sg_image_desc* desc); -SOKOL_GFX_API_DECL void sg_init_sampler(sg_sampler smg, const sg_sampler_desc* desc); -SOKOL_GFX_API_DECL void sg_init_shader(sg_shader shd, const sg_shader_desc* desc); -SOKOL_GFX_API_DECL void sg_init_pipeline(sg_pipeline pip, const sg_pipeline_desc* desc); -SOKOL_GFX_API_DECL void sg_init_attachments(sg_attachments attachments, const sg_attachments_desc* desc); -SOKOL_GFX_API_DECL void sg_uninit_buffer(sg_buffer buf); -SOKOL_GFX_API_DECL void sg_uninit_image(sg_image img); -SOKOL_GFX_API_DECL void sg_uninit_sampler(sg_sampler smp); -SOKOL_GFX_API_DECL void sg_uninit_shader(sg_shader shd); -SOKOL_GFX_API_DECL void sg_uninit_pipeline(sg_pipeline pip); -SOKOL_GFX_API_DECL void sg_uninit_attachments(sg_attachments atts); -SOKOL_GFX_API_DECL void sg_fail_buffer(sg_buffer buf); -SOKOL_GFX_API_DECL void sg_fail_image(sg_image img); -SOKOL_GFX_API_DECL void sg_fail_sampler(sg_sampler smp); -SOKOL_GFX_API_DECL void sg_fail_shader(sg_shader shd); -SOKOL_GFX_API_DECL void sg_fail_pipeline(sg_pipeline pip); -SOKOL_GFX_API_DECL void sg_fail_attachments(sg_attachments atts); - -// frame stats -SOKOL_GFX_API_DECL void sg_enable_frame_stats(void); -SOKOL_GFX_API_DECL void sg_disable_frame_stats(void); -SOKOL_GFX_API_DECL bool sg_frame_stats_enabled(void); -SOKOL_GFX_API_DECL sg_frame_stats sg_query_frame_stats(void); - -/* Backend-specific structs and functions, these may come in handy for mixing - sokol-gfx rendering with 'native backend' rendering functions. - - This group of functions will be expanded as needed. -*/ - -typedef struct sg_d3d11_buffer_info { - const void* buf; // ID3D11Buffer* -} sg_d3d11_buffer_info; - -typedef struct sg_d3d11_image_info { - const void* tex2d; // ID3D11Texture2D* - const void* tex3d; // ID3D11Texture3D* - const void* res; // ID3D11Resource* (either tex2d or tex3d) - const void* srv; // ID3D11ShaderResourceView* -} sg_d3d11_image_info; - -typedef struct sg_d3d11_sampler_info { - const void* smp; // ID3D11SamplerState* -} sg_d3d11_sampler_info; - -typedef struct sg_d3d11_shader_info { - const void* vs_cbufs[SG_MAX_SHADERSTAGE_UBS]; // ID3D11Buffer* (vertex stage constant buffers) - const void* fs_cbufs[SG_MAX_SHADERSTAGE_UBS]; // ID3D11Buffer* (fragment stage constant buffers) - const void* vs; // ID3D11VertexShader* - const void* fs; // ID3D11PixelShader* -} sg_d3d11_shader_info; - -typedef struct sg_d3d11_pipeline_info { - const void* il; // ID3D11InputLayout* - const void* rs; // ID3D11RasterizerState* - const void* dss; // ID3D11DepthStencilState* - const void* bs; // ID3D11BlendState* -} sg_d3d11_pipeline_info; - -typedef struct sg_d3d11_attachments_info { - const void* color_rtv[SG_MAX_COLOR_ATTACHMENTS]; // ID3D11RenderTargetView - const void* resolve_rtv[SG_MAX_COLOR_ATTACHMENTS]; // ID3D11RenderTargetView - const void* dsv; // ID3D11DepthStencilView -} sg_d3d11_attachments_info; - -typedef struct sg_mtl_buffer_info { - const void* buf[SG_NUM_INFLIGHT_FRAMES]; // id - int active_slot; -} sg_mtl_buffer_info; - -typedef struct sg_mtl_image_info { - const void* tex[SG_NUM_INFLIGHT_FRAMES]; // id - int active_slot; -} sg_mtl_image_info; - -typedef struct sg_mtl_sampler_info { - const void* smp; // id -} sg_mtl_sampler_info; - -typedef struct sg_mtl_shader_info { - const void* vs_lib; // id - const void* fs_lib; // id - const void* vs_func; // id - const void* fs_func; // id -} sg_mtl_shader_info; - -typedef struct sg_mtl_pipeline_info { - const void* rps; // id - const void* dss; // id -} sg_mtl_pipeline_info; - -typedef struct sg_wgpu_buffer_info { - const void* buf; // WGPUBuffer -} sg_wgpu_buffer_info; - -typedef struct sg_wgpu_image_info { - const void* tex; // WGPUTexture - const void* view; // WGPUTextureView -} sg_wgpu_image_info; - -typedef struct sg_wgpu_sampler_info { - const void* smp; // WGPUSampler -} sg_wgpu_sampler_info; - -typedef struct sg_wgpu_shader_info { - const void* vs_mod; // WGPUShaderModule - const void* fs_mod; // WGPUShaderModule - const void* bgl; // WGPUBindGroupLayout; -} sg_wgpu_shader_info; - -typedef struct sg_wgpu_pipeline_info { - const void* pip; // WGPURenderPipeline -} sg_wgpu_pipeline_info; - -typedef struct sg_wgpu_attachments_info { - const void* color_view[SG_MAX_COLOR_ATTACHMENTS]; // WGPUTextureView - const void* resolve_view[SG_MAX_COLOR_ATTACHMENTS]; // WGPUTextureView - const void* ds_view; // WGPUTextureView -} sg_wgpu_attachments_info; - -typedef struct sg_gl_buffer_info { - uint32_t buf[SG_NUM_INFLIGHT_FRAMES]; - int active_slot; -} sg_gl_buffer_info; - -typedef struct sg_gl_image_info { - uint32_t tex[SG_NUM_INFLIGHT_FRAMES]; - uint32_t tex_target; - uint32_t msaa_render_buffer; - int active_slot; -} sg_gl_image_info; - -typedef struct sg_gl_sampler_info { - uint32_t smp; -} sg_gl_sampler_info; - -typedef struct sg_gl_shader_info { - uint32_t prog; -} sg_gl_shader_info; - -typedef struct sg_gl_attachments_info { - uint32_t framebuffer; - uint32_t msaa_resolve_framebuffer[SG_MAX_COLOR_ATTACHMENTS]; -} sg_gl_attachments_info; - -// D3D11: return ID3D11Device -SOKOL_GFX_API_DECL const void* sg_d3d11_device(void); -// D3D11: return ID3D11DeviceContext -SOKOL_GFX_API_DECL const void* sg_d3d11_device_context(void); -// D3D11: get internal buffer resource objects -SOKOL_GFX_API_DECL sg_d3d11_buffer_info sg_d3d11_query_buffer_info(sg_buffer buf); -// D3D11: get internal image resource objects -SOKOL_GFX_API_DECL sg_d3d11_image_info sg_d3d11_query_image_info(sg_image img); -// D3D11: get internal sampler resource objects -SOKOL_GFX_API_DECL sg_d3d11_sampler_info sg_d3d11_query_sampler_info(sg_sampler smp); -// D3D11: get internal shader resource objects -SOKOL_GFX_API_DECL sg_d3d11_shader_info sg_d3d11_query_shader_info(sg_shader shd); -// D3D11: get internal pipeline resource objects -SOKOL_GFX_API_DECL sg_d3d11_pipeline_info sg_d3d11_query_pipeline_info(sg_pipeline pip); -// D3D11: get internal pass resource objects -SOKOL_GFX_API_DECL sg_d3d11_attachments_info sg_d3d11_query_attachments_info(sg_attachments atts); - -// Metal: return __bridge-casted MTLDevice -SOKOL_GFX_API_DECL const void* sg_mtl_device(void); -// Metal: return __bridge-casted MTLRenderCommandEncoder in current pass (or zero if outside pass) -SOKOL_GFX_API_DECL const void* sg_mtl_render_command_encoder(void); -// Metal: get internal __bridge-casted buffer resource objects -SOKOL_GFX_API_DECL sg_mtl_buffer_info sg_mtl_query_buffer_info(sg_buffer buf); -// Metal: get internal __bridge-casted image resource objects -SOKOL_GFX_API_DECL sg_mtl_image_info sg_mtl_query_image_info(sg_image img); -// Metal: get internal __bridge-casted sampler resource objects -SOKOL_GFX_API_DECL sg_mtl_sampler_info sg_mtl_query_sampler_info(sg_sampler smp); -// Metal: get internal __bridge-casted shader resource objects -SOKOL_GFX_API_DECL sg_mtl_shader_info sg_mtl_query_shader_info(sg_shader shd); -// Metal: get internal __bridge-casted pipeline resource objects -SOKOL_GFX_API_DECL sg_mtl_pipeline_info sg_mtl_query_pipeline_info(sg_pipeline pip); - -// WebGPU: return WGPUDevice object -SOKOL_GFX_API_DECL const void* sg_wgpu_device(void); -// WebGPU: return WGPUQueue object -SOKOL_GFX_API_DECL const void* sg_wgpu_queue(void); -// WebGPU: return this frame's WGPUCommandEncoder -SOKOL_GFX_API_DECL const void* sg_wgpu_command_encoder(void); -// WebGPU: return WGPURenderPassEncoder of current pass -SOKOL_GFX_API_DECL const void* sg_wgpu_render_pass_encoder(void); -// WebGPU: get internal buffer resource objects -SOKOL_GFX_API_DECL sg_wgpu_buffer_info sg_wgpu_query_buffer_info(sg_buffer buf); -// WebGPU: get internal image resource objects -SOKOL_GFX_API_DECL sg_wgpu_image_info sg_wgpu_query_image_info(sg_image img); -// WebGPU: get internal sampler resource objects -SOKOL_GFX_API_DECL sg_wgpu_sampler_info sg_wgpu_query_sampler_info(sg_sampler smp); -// WebGPU: get internal shader resource objects -SOKOL_GFX_API_DECL sg_wgpu_shader_info sg_wgpu_query_shader_info(sg_shader shd); -// WebGPU: get internal pipeline resource objects -SOKOL_GFX_API_DECL sg_wgpu_pipeline_info sg_wgpu_query_pipeline_info(sg_pipeline pip); -// WebGPU: get internal pass resource objects -SOKOL_GFX_API_DECL sg_wgpu_attachments_info sg_wgpu_query_attachments_info(sg_attachments atts); - -// GL: get internal buffer resource objects -SOKOL_GFX_API_DECL sg_gl_buffer_info sg_gl_query_buffer_info(sg_buffer buf); -// GL: get internal image resource objects -SOKOL_GFX_API_DECL sg_gl_image_info sg_gl_query_image_info(sg_image img); -// GL: get internal sampler resource objects -SOKOL_GFX_API_DECL sg_gl_sampler_info sg_gl_query_sampler_info(sg_sampler smp); -// GL: get internal shader resource objects -SOKOL_GFX_API_DECL sg_gl_shader_info sg_gl_query_shader_info(sg_shader shd); -// GL: get internal pass resource objects -SOKOL_GFX_API_DECL sg_gl_attachments_info sg_gl_query_attachments_info(sg_attachments atts); - -#ifdef __cplusplus -} // extern "C" - -// reference-based equivalents for c++ -inline void sg_setup(const sg_desc& desc) { return sg_setup(&desc); } - -inline sg_buffer sg_make_buffer(const sg_buffer_desc& desc) { return sg_make_buffer(&desc); } -inline sg_image sg_make_image(const sg_image_desc& desc) { return sg_make_image(&desc); } -inline sg_sampler sg_make_sampler(const sg_sampler_desc& desc) { return sg_make_sampler(&desc); } -inline sg_shader sg_make_shader(const sg_shader_desc& desc) { return sg_make_shader(&desc); } -inline sg_pipeline sg_make_pipeline(const sg_pipeline_desc& desc) { return sg_make_pipeline(&desc); } -inline sg_attachments sg_make_attachments(const sg_attachments_desc& desc) { return sg_make_attachments(&desc); } -inline void sg_update_image(sg_image img, const sg_image_data& data) { return sg_update_image(img, &data); } - -inline void sg_begin_pass(const sg_pass& pass) { return sg_begin_pass(&pass); } -inline void sg_apply_bindings(const sg_bindings& bindings) { return sg_apply_bindings(&bindings); } -inline void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range& data) { return sg_apply_uniforms(stage, ub_index, &data); } - -inline sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc& desc) { return sg_query_buffer_defaults(&desc); } -inline sg_image_desc sg_query_image_defaults(const sg_image_desc& desc) { return sg_query_image_defaults(&desc); } -inline sg_sampler_desc sg_query_sampler_defaults(const sg_sampler_desc& desc) { return sg_query_sampler_defaults(&desc); } -inline sg_shader_desc sg_query_shader_defaults(const sg_shader_desc& desc) { return sg_query_shader_defaults(&desc); } -inline sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc& desc) { return sg_query_pipeline_defaults(&desc); } -inline sg_attachments_desc sg_query_attachments_defaults(const sg_attachments_desc& desc) { return sg_query_attachments_defaults(&desc); } - -inline void sg_init_buffer(sg_buffer buf, const sg_buffer_desc& desc) { return sg_init_buffer(buf, &desc); } -inline void sg_init_image(sg_image img, const sg_image_desc& desc) { return sg_init_image(img, &desc); } -inline void sg_init_sampler(sg_sampler smp, const sg_sampler_desc& desc) { return sg_init_sampler(smp, &desc); } -inline void sg_init_shader(sg_shader shd, const sg_shader_desc& desc) { return sg_init_shader(shd, &desc); } -inline void sg_init_pipeline(sg_pipeline pip, const sg_pipeline_desc& desc) { return sg_init_pipeline(pip, &desc); } -inline void sg_init_attachments(sg_attachments atts, const sg_attachments_desc& desc) { return sg_init_attachments(atts, &desc); } - -inline void sg_update_buffer(sg_buffer buf_id, const sg_range& data) { return sg_update_buffer(buf_id, &data); } -inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_append_buffer(buf_id, &data); } -#endif -#endif // SOKOL_GFX_INCLUDED - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_GFX_IMPL -#define SOKOL_GFX_IMPL_INCLUDED (1) - -#if !(defined(SOKOL_GLCORE)||defined(SOKOL_GLES3)||defined(SOKOL_D3D11)||defined(SOKOL_METAL)||defined(SOKOL_WGPU)||defined(SOKOL_DUMMY_BACKEND)) -#error "Please select a backend with SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND" -#endif -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sg_desc.allocator to override memory allocation functions" -#endif - -#include // malloc, free -#include // memset -#include // FLT_MAX - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif - -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -#ifndef _SOKOL_UNUSED - #define _SOKOL_UNUSED(x) (void)(x) -#endif - -#if defined(SOKOL_TRACE_HOOKS) -#define _SG_TRACE_ARGS(fn, ...) if (_sg.hooks.fn) { _sg.hooks.fn(__VA_ARGS__, _sg.hooks.user_data); } -#define _SG_TRACE_NOARGS(fn) if (_sg.hooks.fn) { _sg.hooks.fn(_sg.hooks.user_data); } -#else -#define _SG_TRACE_ARGS(fn, ...) -#define _SG_TRACE_NOARGS(fn) -#endif - -// default clear values -#ifndef SG_DEFAULT_CLEAR_RED -#define SG_DEFAULT_CLEAR_RED (0.5f) -#endif -#ifndef SG_DEFAULT_CLEAR_GREEN -#define SG_DEFAULT_CLEAR_GREEN (0.5f) -#endif -#ifndef SG_DEFAULT_CLEAR_BLUE -#define SG_DEFAULT_CLEAR_BLUE (0.5f) -#endif -#ifndef SG_DEFAULT_CLEAR_ALPHA -#define SG_DEFAULT_CLEAR_ALPHA (1.0f) -#endif -#ifndef SG_DEFAULT_CLEAR_DEPTH -#define SG_DEFAULT_CLEAR_DEPTH (1.0f) -#endif -#ifndef SG_DEFAULT_CLEAR_STENCIL -#define SG_DEFAULT_CLEAR_STENCIL (0) -#endif - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4115) // named type definition in parentheses -#pragma warning(disable:4505) // unreferenced local function has been removed -#pragma warning(disable:4201) // nonstandard extension used: nameless struct/union (needed by d3d11.h) -#pragma warning(disable:4054) // 'type cast': from function pointer -#pragma warning(disable:4055) // 'type cast': from data pointer -#endif - -#if defined(SOKOL_D3D11) - #ifndef D3D11_NO_HELPERS - #define D3D11_NO_HELPERS - #endif - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - #ifndef NOMINMAX - #define NOMINMAX - #endif - #include - #include - #ifdef _MSC_VER - #pragma comment (lib, "kernel32") - #pragma comment (lib, "user32") - #pragma comment (lib, "dxgi") - #pragma comment (lib, "d3d11") - #endif -#elif defined(SOKOL_METAL) - // see https://clang.llvm.org/docs/LanguageExtensions.html#automatic-reference-counting - #if !defined(__cplusplus) - #if __has_feature(objc_arc) && !__has_feature(objc_arc_fields) - #error "sokol_gfx.h requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)" - #endif - #endif - #include - #include - #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE - #define _SG_TARGET_MACOS (1) - #else - #define _SG_TARGET_IOS (1) - #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR - #define _SG_TARGET_IOS_SIMULATOR (1) - #endif - #endif - #import - #import // needed for CAMetalDrawable -#elif defined(SOKOL_WGPU) - #include - #if defined(__EMSCRIPTEN__) - #include - #endif -#elif defined(SOKOL_GLCORE) || defined(SOKOL_GLES3) - #define _SOKOL_ANY_GL (1) - - // include platform specific GL headers (or on Win32: use an embedded GL loader) - #if !defined(SOKOL_EXTERNAL_GL_LOADER) - #if defined(_WIN32) - #if defined(SOKOL_GLCORE) && !defined(SOKOL_EXTERNAL_GL_LOADER) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - #ifndef NOMINMAX - #define NOMINMAX - #endif - #include - #define _SOKOL_USE_WIN32_GL_LOADER (1) - #pragma comment (lib, "kernel32") // GetProcAddress() - #endif - #elif defined(__APPLE__) - #include - #ifndef GL_SILENCE_DEPRECATION - #define GL_SILENCE_DEPRECATION - #endif - #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE - #include - #else - #include - #include - #endif - #elif defined(__EMSCRIPTEN__) || defined(__ANDROID__) - #if defined(SOKOL_GLES3) - #include - #endif - #elif defined(__linux__) || defined(__unix__) - #if defined(SOKOL_GLCORE) - #define GL_GLEXT_PROTOTYPES - #include - #else - #include - #include - #endif - #endif - #endif - - // optional GL loader definitions (only on Win32) - #if defined(_SOKOL_USE_WIN32_GL_LOADER) - #define __gl_h_ 1 - #define __gl32_h_ 1 - #define __gl31_h_ 1 - #define __GL_H__ 1 - #define __glext_h_ 1 - #define __GLEXT_H_ 1 - #define __gltypes_h_ 1 - #define __glcorearb_h_ 1 - #define __gl_glcorearb_h_ 1 - #define GL_APIENTRY APIENTRY - - typedef unsigned int GLenum; - typedef unsigned int GLuint; - typedef int GLsizei; - typedef char GLchar; - typedef ptrdiff_t GLintptr; - typedef ptrdiff_t GLsizeiptr; - typedef double GLclampd; - typedef unsigned short GLushort; - typedef unsigned char GLubyte; - typedef unsigned char GLboolean; - typedef uint64_t GLuint64; - typedef double GLdouble; - typedef unsigned short GLhalf; - typedef float GLclampf; - typedef unsigned int GLbitfield; - typedef signed char GLbyte; - typedef short GLshort; - typedef void GLvoid; - typedef int64_t GLint64; - typedef float GLfloat; - typedef int GLint; - #define GL_INT_2_10_10_10_REV 0x8D9F - #define GL_R32F 0x822E - #define GL_PROGRAM_POINT_SIZE 0x8642 - #define GL_DEPTH_ATTACHMENT 0x8D00 - #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A - #define GL_COLOR_ATTACHMENT2 0x8CE2 - #define GL_COLOR_ATTACHMENT0 0x8CE0 - #define GL_R16F 0x822D - #define GL_COLOR_ATTACHMENT22 0x8CF6 - #define GL_DRAW_FRAMEBUFFER 0x8CA9 - #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 - #define GL_NUM_EXTENSIONS 0x821D - #define GL_INFO_LOG_LENGTH 0x8B84 - #define GL_VERTEX_SHADER 0x8B31 - #define GL_INCR 0x1E02 - #define GL_DYNAMIC_DRAW 0x88E8 - #define GL_STATIC_DRAW 0x88E4 - #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 - #define GL_TEXTURE_CUBE_MAP 0x8513 - #define GL_FUNC_SUBTRACT 0x800A - #define GL_FUNC_REVERSE_SUBTRACT 0x800B - #define GL_CONSTANT_COLOR 0x8001 - #define GL_DECR_WRAP 0x8508 - #define GL_R8 0x8229 - #define GL_LINEAR_MIPMAP_LINEAR 0x2703 - #define GL_ELEMENT_ARRAY_BUFFER 0x8893 - #define GL_SHORT 0x1402 - #define GL_DEPTH_TEST 0x0B71 - #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 - #define GL_LINK_STATUS 0x8B82 - #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 - #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E - #define GL_RGBA16F 0x881A - #define GL_CONSTANT_ALPHA 0x8003 - #define GL_READ_FRAMEBUFFER 0x8CA8 - #define GL_TEXTURE0 0x84C0 - #define GL_TEXTURE_MIN_LOD 0x813A - #define GL_CLAMP_TO_EDGE 0x812F - #define GL_UNSIGNED_SHORT_5_6_5 0x8363 - #define GL_TEXTURE_WRAP_R 0x8072 - #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 - #define GL_NEAREST_MIPMAP_NEAREST 0x2700 - #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 - #define GL_SRC_ALPHA_SATURATE 0x0308 - #define GL_STREAM_DRAW 0x88E0 - #define GL_ONE 1 - #define GL_NEAREST_MIPMAP_LINEAR 0x2702 - #define GL_RGB10_A2 0x8059 - #define GL_RGBA8 0x8058 - #define GL_SRGB8_ALPHA8 0x8C43 - #define GL_COLOR_ATTACHMENT1 0x8CE1 - #define GL_RGBA4 0x8056 - #define GL_RGB8 0x8051 - #define GL_ARRAY_BUFFER 0x8892 - #define GL_STENCIL 0x1802 - #define GL_TEXTURE_2D 0x0DE1 - #define GL_DEPTH 0x1801 - #define GL_FRONT 0x0404 - #define GL_STENCIL_BUFFER_BIT 0x00000400 - #define GL_REPEAT 0x2901 - #define GL_RGBA 0x1908 - #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 - #define GL_DECR 0x1E03 - #define GL_FRAGMENT_SHADER 0x8B30 - #define GL_FLOAT 0x1406 - #define GL_TEXTURE_MAX_LOD 0x813B - #define GL_DEPTH_COMPONENT 0x1902 - #define GL_ONE_MINUS_DST_ALPHA 0x0305 - #define GL_COLOR 0x1800 - #define GL_TEXTURE_2D_ARRAY 0x8C1A - #define GL_TRIANGLES 0x0004 - #define GL_UNSIGNED_BYTE 0x1401 - #define GL_TEXTURE_MAG_FILTER 0x2800 - #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 - #define GL_NONE 0 - #define GL_SRC_COLOR 0x0300 - #define GL_BYTE 0x1400 - #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A - #define GL_LINE_STRIP 0x0003 - #define GL_TEXTURE_3D 0x806F - #define GL_CW 0x0900 - #define GL_LINEAR 0x2601 - #define GL_RENDERBUFFER 0x8D41 - #define GL_GEQUAL 0x0206 - #define GL_COLOR_BUFFER_BIT 0x00004000 - #define GL_RGBA32F 0x8814 - #define GL_BLEND 0x0BE2 - #define GL_ONE_MINUS_SRC_ALPHA 0x0303 - #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 - #define GL_TEXTURE_WRAP_T 0x2803 - #define GL_TEXTURE_WRAP_S 0x2802 - #define GL_TEXTURE_MIN_FILTER 0x2801 - #define GL_LINEAR_MIPMAP_NEAREST 0x2701 - #define GL_EXTENSIONS 0x1F03 - #define GL_NO_ERROR 0 - #define GL_REPLACE 0x1E01 - #define GL_KEEP 0x1E00 - #define GL_CCW 0x0901 - #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 - #define GL_RGB 0x1907 - #define GL_TRIANGLE_STRIP 0x0005 - #define GL_FALSE 0 - #define GL_ZERO 0 - #define GL_CULL_FACE 0x0B44 - #define GL_INVERT 0x150A - #define GL_INT 0x1404 - #define GL_UNSIGNED_INT 0x1405 - #define GL_UNSIGNED_SHORT 0x1403 - #define GL_NEAREST 0x2600 - #define GL_SCISSOR_TEST 0x0C11 - #define GL_LEQUAL 0x0203 - #define GL_STENCIL_TEST 0x0B90 - #define GL_DITHER 0x0BD0 - #define GL_DEPTH_COMPONENT32F 0x8CAC - #define GL_EQUAL 0x0202 - #define GL_FRAMEBUFFER 0x8D40 - #define GL_RGB5 0x8050 - #define GL_LINES 0x0001 - #define GL_DEPTH_BUFFER_BIT 0x00000100 - #define GL_SRC_ALPHA 0x0302 - #define GL_INCR_WRAP 0x8507 - #define GL_LESS 0x0201 - #define GL_MULTISAMPLE 0x809D - #define GL_FRAMEBUFFER_BINDING 0x8CA6 - #define GL_BACK 0x0405 - #define GL_ALWAYS 0x0207 - #define GL_FUNC_ADD 0x8006 - #define GL_ONE_MINUS_DST_COLOR 0x0307 - #define GL_NOTEQUAL 0x0205 - #define GL_DST_COLOR 0x0306 - #define GL_COMPILE_STATUS 0x8B81 - #define GL_RED 0x1903 - #define GL_COLOR_ATTACHMENT3 0x8CE3 - #define GL_DST_ALPHA 0x0304 - #define GL_RGB5_A1 0x8057 - #define GL_GREATER 0x0204 - #define GL_POLYGON_OFFSET_FILL 0x8037 - #define GL_TRUE 1 - #define GL_NEVER 0x0200 - #define GL_POINTS 0x0000 - #define GL_ONE_MINUS_SRC_COLOR 0x0301 - #define GL_MIRRORED_REPEAT 0x8370 - #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D - #define GL_R11F_G11F_B10F 0x8C3A - #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B - #define GL_RGB9_E5 0x8C3D - #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E - #define GL_RGBA32UI 0x8D70 - #define GL_RGB32UI 0x8D71 - #define GL_RGBA16UI 0x8D76 - #define GL_RGB16UI 0x8D77 - #define GL_RGBA8UI 0x8D7C - #define GL_RGB8UI 0x8D7D - #define GL_RGBA32I 0x8D82 - #define GL_RGB32I 0x8D83 - #define GL_RGBA16I 0x8D88 - #define GL_RGB16I 0x8D89 - #define GL_RGBA8I 0x8D8E - #define GL_RGB8I 0x8D8F - #define GL_RED_INTEGER 0x8D94 - #define GL_RG 0x8227 - #define GL_RG_INTEGER 0x8228 - #define GL_R8 0x8229 - #define GL_R16 0x822A - #define GL_RG8 0x822B - #define GL_RG16 0x822C - #define GL_R16F 0x822D - #define GL_R32F 0x822E - #define GL_RG16F 0x822F - #define GL_RG32F 0x8230 - #define GL_R8I 0x8231 - #define GL_R8UI 0x8232 - #define GL_R16I 0x8233 - #define GL_R16UI 0x8234 - #define GL_R32I 0x8235 - #define GL_R32UI 0x8236 - #define GL_RG8I 0x8237 - #define GL_RG8UI 0x8238 - #define GL_RG16I 0x8239 - #define GL_RG16UI 0x823A - #define GL_RG32I 0x823B - #define GL_RG32UI 0x823C - #define GL_RGBA_INTEGER 0x8D99 - #define GL_R8_SNORM 0x8F94 - #define GL_RG8_SNORM 0x8F95 - #define GL_RGB8_SNORM 0x8F96 - #define GL_RGBA8_SNORM 0x8F97 - #define GL_R16_SNORM 0x8F98 - #define GL_RG16_SNORM 0x8F99 - #define GL_RGB16_SNORM 0x8F9A - #define GL_RGBA16_SNORM 0x8F9B - #define GL_RGBA16 0x805B - #define GL_MAX_TEXTURE_SIZE 0x0D33 - #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C - #define GL_MAX_3D_TEXTURE_SIZE 0x8073 - #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF - #define GL_MAX_VERTEX_ATTRIBS 0x8869 - #define GL_CLAMP_TO_BORDER 0x812D - #define GL_TEXTURE_BORDER_COLOR 0x1004 - #define GL_CURRENT_PROGRAM 0x8B8D - #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A - #define GL_UNPACK_ALIGNMENT 0x0CF5 - #define GL_FRAMEBUFFER_SRGB 0x8DB9 - #define GL_TEXTURE_COMPARE_MODE 0x884C - #define GL_TEXTURE_COMPARE_FUNC 0x884D - #define GL_COMPARE_REF_TO_TEXTURE 0x884E - #define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F - #define GL_TEXTURE_MAX_LEVEL 0x813D - #define GL_FRAMEBUFFER_UNDEFINED 0x8219 - #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 - #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 - #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD - #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 - #define GL_MAJOR_VERSION 0x821B - #define GL_MINOR_VERSION 0x821C - #endif - - #ifndef GL_UNSIGNED_INT_2_10_10_10_REV - #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 - #endif - #ifndef GL_UNSIGNED_INT_24_8 - #define GL_UNSIGNED_INT_24_8 0x84FA - #endif - #ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT - #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE - #endif - #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT - #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF - #endif - #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT - #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 - #endif - #ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT - #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 - #endif - #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT - #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 - #endif - #ifndef GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT - #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F - #endif - #ifndef GL_COMPRESSED_RED_RGTC1 - #define GL_COMPRESSED_RED_RGTC1 0x8DBB - #endif - #ifndef GL_COMPRESSED_SIGNED_RED_RGTC1 - #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC - #endif - #ifndef GL_COMPRESSED_RED_GREEN_RGTC2 - #define GL_COMPRESSED_RED_GREEN_RGTC2 0x8DBD - #endif - #ifndef GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2 - #define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2 0x8DBE - #endif - #ifndef GL_COMPRESSED_RGBA_BPTC_UNORM_ARB - #define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C - #endif - #ifndef GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB - #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D - #endif - #ifndef GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB - #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E - #endif - #ifndef GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB - #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F - #endif - #ifndef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG - #define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 - #endif - #ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG - #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 - #endif - #ifndef GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG - #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 - #endif - #ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG - #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 - #endif - #ifndef GL_COMPRESSED_RGB8_ETC2 - #define GL_COMPRESSED_RGB8_ETC2 0x9274 - #endif - #ifndef GL_COMPRESSED_SRGB8_ETC2 - #define GL_COMPRESSED_SRGB8_ETC2 0x9275 - #endif - #ifndef GL_COMPRESSED_RGBA8_ETC2_EAC - #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 - #endif - #ifndef GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC - #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 - #endif - #ifndef GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 - #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 - #endif - #ifndef GL_COMPRESSED_R11_EAC - #define GL_COMPRESSED_R11_EAC 0x9270 - #endif - #ifndef GL_COMPRESSED_SIGNED_R11_EAC - #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 - #endif - #ifndef GL_COMPRESSED_RG11_EAC - #define GL_COMPRESSED_RG11_EAC 0x9272 - #endif - #ifndef GL_COMPRESSED_SIGNED_RG11_EAC - #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 - #endif - #ifndef GL_COMPRESSED_RGBA_ASTC_4x4_KHR - #define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 - #endif - #ifndef GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR - #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 - #endif - #ifndef GL_DEPTH24_STENCIL8 - #define GL_DEPTH24_STENCIL8 0x88F0 - #endif - #ifndef GL_HALF_FLOAT - #define GL_HALF_FLOAT 0x140B - #endif - #ifndef GL_DEPTH_STENCIL - #define GL_DEPTH_STENCIL 0x84F9 - #endif - #ifndef GL_LUMINANCE - #define GL_LUMINANCE 0x1909 - #endif - #ifndef _SG_GL_CHECK_ERROR - #define _SG_GL_CHECK_ERROR() { SOKOL_ASSERT(glGetError() == GL_NO_ERROR); } - #endif -#endif - -#if defined(SOKOL_GLES3) - // on WebGL2, GL_FRAMEBUFFER_UNDEFINED technically doesn't exist (it is defined - // in the Emscripten headers, but may not exist in other WebGL2 shims) - // see: https://github.com/floooh/sokol/pull/933 - #ifndef GL_FRAMEBUFFER_UNDEFINED - #define GL_FRAMEBUFFER_UNDEFINED 0x8219 - #endif -#endif - -// make some GL constants generally available to simplify compilation, -// use of those constants will be filtered by runtime flags -#ifndef GL_SHADER_STORAGE_BUFFER -#define GL_SHADER_STORAGE_BUFFER 0x90D2 -#endif - -// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██████ ██ ██ ██ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██████ ██████ ██ ███████ -// -// >>structs -// resource pool slots -typedef struct { - uint32_t id; - sg_resource_state state; -} _sg_slot_t; - -// resource pool housekeeping struct -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _sg_pool_t; - -_SOKOL_PRIVATE void _sg_init_pool(_sg_pool_t* pool, int num); -_SOKOL_PRIVATE void _sg_discard_pool(_sg_pool_t* pool); -_SOKOL_PRIVATE int _sg_pool_alloc_index(_sg_pool_t* pool); -_SOKOL_PRIVATE void _sg_pool_free_index(_sg_pool_t* pool, int slot_index); -_SOKOL_PRIVATE void _sg_reset_slot(_sg_slot_t* slot); -_SOKOL_PRIVATE uint32_t _sg_slot_alloc(_sg_pool_t* pool, _sg_slot_t* slot, int slot_index); -_SOKOL_PRIVATE int _sg_slot_index(uint32_t id); - -// constants -enum { - _SG_STRING_SIZE = 32, - _SG_SLOT_SHIFT = 16, - _SG_SLOT_MASK = (1<<_SG_SLOT_SHIFT)-1, - _SG_MAX_POOL_SIZE = (1<<_SG_SLOT_SHIFT), - _SG_DEFAULT_BUFFER_POOL_SIZE = 128, - _SG_DEFAULT_IMAGE_POOL_SIZE = 128, - _SG_DEFAULT_SAMPLER_POOL_SIZE = 64, - _SG_DEFAULT_SHADER_POOL_SIZE = 32, - _SG_DEFAULT_PIPELINE_POOL_SIZE = 64, - _SG_DEFAULT_ATTACHMENTS_POOL_SIZE = 16, - _SG_DEFAULT_UB_SIZE = 4 * 1024 * 1024, - _SG_DEFAULT_MAX_COMMIT_LISTENERS = 1024, - _SG_DEFAULT_WGPU_BINDGROUP_CACHE_SIZE = 1024, -}; - -// fixed-size string -typedef struct { - char buf[_SG_STRING_SIZE]; -} _sg_str_t; - -// helper macros -#define _sg_def(val, def) (((val) == 0) ? (def) : (val)) -#define _sg_def_flt(val, def) (((val) == 0.0f) ? (def) : (val)) -#define _sg_min(a,b) (((a)<(b))?(a):(b)) -#define _sg_max(a,b) (((a)>(b))?(a):(b)) -#define _sg_clamp(v,v0,v1) (((v)<(v0))?(v0):(((v)>(v1))?(v1):(v))) -#define _sg_fequal(val,cmp,delta) ((((val)-(cmp))> -(delta))&&(((val)-(cmp))<(delta))) -#define _sg_ispow2(val) ((val&(val-1))==0) -#define _sg_stats_add(key,val) {if(_sg.stats_enabled){ _sg.stats.key+=val;}} - -_SOKOL_PRIVATE void* _sg_malloc_clear(size_t size); -_SOKOL_PRIVATE void _sg_free(void* ptr); -_SOKOL_PRIVATE void _sg_clear(void* ptr, size_t size); - -typedef struct { - int size; - int append_pos; - bool append_overflow; - uint32_t update_frame_index; - uint32_t append_frame_index; - int num_slots; - int active_slot; - sg_buffer_type type; - sg_usage usage; -} _sg_buffer_common_t; - -_SOKOL_PRIVATE void _sg_buffer_common_init(_sg_buffer_common_t* cmn, const sg_buffer_desc* desc) { - cmn->size = (int)desc->size; - cmn->append_pos = 0; - cmn->append_overflow = false; - cmn->update_frame_index = 0; - cmn->append_frame_index = 0; - cmn->num_slots = (desc->usage == SG_USAGE_IMMUTABLE) ? 1 : SG_NUM_INFLIGHT_FRAMES; - cmn->active_slot = 0; - cmn->type = desc->type; - cmn->usage = desc->usage; -} - -typedef struct { - uint32_t upd_frame_index; - int num_slots; - int active_slot; - sg_image_type type; - bool render_target; - int width; - int height; - int num_slices; - int num_mipmaps; - sg_usage usage; - sg_pixel_format pixel_format; - int sample_count; -} _sg_image_common_t; - -_SOKOL_PRIVATE void _sg_image_common_init(_sg_image_common_t* cmn, const sg_image_desc* desc) { - cmn->upd_frame_index = 0; - cmn->num_slots = (desc->usage == SG_USAGE_IMMUTABLE) ? 1 : SG_NUM_INFLIGHT_FRAMES; - cmn->active_slot = 0; - cmn->type = desc->type; - cmn->render_target = desc->render_target; - cmn->width = desc->width; - cmn->height = desc->height; - cmn->num_slices = desc->num_slices; - cmn->num_mipmaps = desc->num_mipmaps; - cmn->usage = desc->usage; - cmn->pixel_format = desc->pixel_format; - cmn->sample_count = desc->sample_count; -} - -typedef struct { - sg_filter min_filter; - sg_filter mag_filter; - sg_filter mipmap_filter; - sg_wrap wrap_u; - sg_wrap wrap_v; - sg_wrap wrap_w; - float min_lod; - float max_lod; - sg_border_color border_color; - sg_compare_func compare; - uint32_t max_anisotropy; -} _sg_sampler_common_t; - -_SOKOL_PRIVATE void _sg_sampler_common_init(_sg_sampler_common_t* cmn, const sg_sampler_desc* desc) { - cmn->min_filter = desc->min_filter; - cmn->mag_filter = desc->mag_filter; - cmn->mipmap_filter = desc->mipmap_filter; - cmn->wrap_u = desc->wrap_u; - cmn->wrap_v = desc->wrap_v; - cmn->wrap_w = desc->wrap_w; - cmn->min_lod = desc->min_lod; - cmn->max_lod = desc->max_lod; - cmn->border_color = desc->border_color; - cmn->compare = desc->compare; - cmn->max_anisotropy = desc->max_anisotropy; -} - -typedef struct { - size_t size; -} _sg_shader_uniform_block_t; - -typedef struct { - bool used; - bool readonly; -} _sg_shader_storage_buffer_t; - -typedef struct { - sg_image_type image_type; - sg_image_sample_type sample_type; - bool multisampled; -} _sg_shader_image_t; - -typedef struct { - sg_sampler_type sampler_type; -} _sg_shader_sampler_t; - -// combined image sampler mappings, only needed on GL -typedef struct { - int image_slot; - int sampler_slot; -} _sg_shader_image_sampler_t; - -typedef struct { - int num_uniform_blocks; - int num_storage_buffers; - int num_images; - int num_samplers; - int num_image_samplers; - _sg_shader_uniform_block_t uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; - _sg_shader_storage_buffer_t storage_buffers[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; - _sg_shader_image_t images[SG_MAX_SHADERSTAGE_IMAGES]; - _sg_shader_sampler_t samplers[SG_MAX_SHADERSTAGE_SAMPLERS]; - _sg_shader_image_sampler_t image_samplers[SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]; -} _sg_shader_stage_t; - -typedef struct { - _sg_shader_stage_t stage[SG_NUM_SHADER_STAGES]; -} _sg_shader_common_t; - -_SOKOL_PRIVATE void _sg_shader_common_init(_sg_shader_common_t* cmn, const sg_shader_desc* desc) { - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS) ? &desc->vs : &desc->fs; - _sg_shader_stage_t* stage = &cmn->stage[stage_index]; - SOKOL_ASSERT(stage->num_uniform_blocks == 0); - for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { - const sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index]; - if (0 == ub_desc->size) { - break; - } - stage->uniform_blocks[ub_index].size = ub_desc->size; - stage->num_uniform_blocks++; - } - SOKOL_ASSERT(stage->num_images == 0); - for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { - const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; - if (!img_desc->used) { - break; - } - stage->images[img_index].multisampled = img_desc->multisampled; - stage->images[img_index].image_type = img_desc->image_type; - stage->images[img_index].sample_type = img_desc->sample_type; - stage->num_images++; - } - SOKOL_ASSERT(stage->num_samplers == 0); - for (int smp_index = 0; smp_index < SG_MAX_SHADERSTAGE_SAMPLERS; smp_index++) { - const sg_shader_sampler_desc* smp_desc = &stage_desc->samplers[smp_index]; - if (!smp_desc->used) { - break; - } - stage->samplers[smp_index].sampler_type = smp_desc->sampler_type; - stage->num_samplers++; - } - SOKOL_ASSERT(stage->num_image_samplers == 0); - for (int img_smp_index = 0; img_smp_index < SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS; img_smp_index++) { - const sg_shader_image_sampler_pair_desc* img_smp_desc = &stage_desc->image_sampler_pairs[img_smp_index]; - if (!img_smp_desc->used) { - break; - } - SOKOL_ASSERT((img_smp_desc->image_slot >= 0) && (img_smp_desc->image_slot < stage->num_images)); - stage->image_samplers[img_smp_index].image_slot = img_smp_desc->image_slot; - SOKOL_ASSERT((img_smp_desc->sampler_slot >= 0) && (img_smp_desc->sampler_slot < stage->num_samplers)); - stage->image_samplers[img_smp_index].sampler_slot = img_smp_desc->sampler_slot; - stage->num_image_samplers++; - } - SOKOL_ASSERT(stage->num_storage_buffers == 0); - for (int sbuf_index = 0; sbuf_index < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; sbuf_index++) { - const sg_shader_storage_buffer_desc* sbuf_desc = &stage_desc->storage_buffers[sbuf_index]; - if (!sbuf_desc->used) { - break; - } - stage->storage_buffers[sbuf_index].used = sbuf_desc->used; - stage->storage_buffers[sbuf_index].readonly = sbuf_desc->readonly; - stage->num_storage_buffers++; - } - } -} - -typedef struct { - bool vertex_buffer_layout_active[SG_MAX_VERTEX_BUFFERS]; - bool use_instanced_draw; - sg_shader shader_id; - sg_vertex_layout_state layout; - sg_depth_state depth; - sg_stencil_state stencil; - int color_count; - sg_color_target_state colors[SG_MAX_COLOR_ATTACHMENTS]; - sg_primitive_type primitive_type; - sg_index_type index_type; - sg_cull_mode cull_mode; - sg_face_winding face_winding; - int sample_count; - sg_color blend_color; - bool alpha_to_coverage_enabled; -} _sg_pipeline_common_t; - -_SOKOL_PRIVATE void _sg_pipeline_common_init(_sg_pipeline_common_t* cmn, const sg_pipeline_desc* desc) { - SOKOL_ASSERT((desc->color_count >= 0) && (desc->color_count <= SG_MAX_COLOR_ATTACHMENTS)); - for (int i = 0; i < SG_MAX_VERTEX_BUFFERS; i++) { - cmn->vertex_buffer_layout_active[i] = false; - } - cmn->use_instanced_draw = false; - cmn->shader_id = desc->shader; - cmn->layout = desc->layout; - cmn->depth = desc->depth; - cmn->stencil = desc->stencil; - cmn->color_count = desc->color_count; - for (int i = 0; i < desc->color_count; i++) { - cmn->colors[i] = desc->colors[i]; - } - cmn->primitive_type = desc->primitive_type; - cmn->index_type = desc->index_type; - cmn->cull_mode = desc->cull_mode; - cmn->face_winding = desc->face_winding; - cmn->sample_count = desc->sample_count; - cmn->blend_color = desc->blend_color; - cmn->alpha_to_coverage_enabled = desc->alpha_to_coverage_enabled; -} - -typedef struct { - sg_image image_id; - int mip_level; - int slice; -} _sg_attachment_common_t; - -typedef struct { - int width; - int height; - int num_colors; - _sg_attachment_common_t colors[SG_MAX_COLOR_ATTACHMENTS]; - _sg_attachment_common_t resolves[SG_MAX_COLOR_ATTACHMENTS]; - _sg_attachment_common_t depth_stencil; -} _sg_attachments_common_t; - -_SOKOL_PRIVATE void _sg_attachment_common_init(_sg_attachment_common_t* cmn, const sg_attachment_desc* desc) { - cmn->image_id = desc->image; - cmn->mip_level = desc->mip_level; - cmn->slice = desc->slice; -} - -_SOKOL_PRIVATE void _sg_attachments_common_init(_sg_attachments_common_t* cmn, const sg_attachments_desc* desc, int width, int height) { - SOKOL_ASSERT((width > 0) && (height > 0)); - cmn->width = width; - cmn->height = height; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (desc->colors[i].image.id != SG_INVALID_ID) { - cmn->num_colors++; - _sg_attachment_common_init(&cmn->colors[i], &desc->colors[i]); - _sg_attachment_common_init(&cmn->resolves[i], &desc->resolves[i]); - } - } - if (desc->depth_stencil.image.id != SG_INVALID_ID) { - _sg_attachment_common_init(&cmn->depth_stencil, &desc->depth_stencil); - } -} - -#if defined(SOKOL_DUMMY_BACKEND) -typedef struct { - _sg_slot_t slot; - _sg_buffer_common_t cmn; -} _sg_dummy_buffer_t; -typedef _sg_dummy_buffer_t _sg_buffer_t; - -typedef struct { - _sg_slot_t slot; - _sg_image_common_t cmn; -} _sg_dummy_image_t; -typedef _sg_dummy_image_t _sg_image_t; - -typedef struct { - _sg_slot_t slot; - _sg_sampler_common_t cmn; -} _sg_dummy_sampler_t; -typedef _sg_dummy_sampler_t _sg_sampler_t; - -typedef struct { - _sg_slot_t slot; - _sg_shader_common_t cmn; -} _sg_dummy_shader_t; -typedef _sg_dummy_shader_t _sg_shader_t; - -typedef struct { - _sg_slot_t slot; - _sg_shader_t* shader; - _sg_pipeline_common_t cmn; -} _sg_dummy_pipeline_t; -typedef _sg_dummy_pipeline_t _sg_pipeline_t; - -typedef struct { - _sg_image_t* image; -} _sg_dummy_attachment_t; - -typedef struct { - _sg_slot_t slot; - _sg_attachments_common_t cmn; - struct { - _sg_dummy_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; - _sg_dummy_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; - _sg_dummy_attachment_t depth_stencil; - } dmy; -} _sg_dummy_attachments_t; -typedef _sg_dummy_attachments_t _sg_attachments_t; - -#elif defined(_SOKOL_ANY_GL) - -#define _SG_GL_TEXTURE_SAMPLER_CACHE_SIZE (SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS * SG_NUM_SHADER_STAGES) -#define _SG_GL_STORAGEBUFFER_STAGE_INDEX_PITCH (SG_MAX_SHADERSTAGE_STORAGEBUFFERS) - -typedef struct { - _sg_slot_t slot; - _sg_buffer_common_t cmn; - struct { - GLuint buf[SG_NUM_INFLIGHT_FRAMES]; - bool injected; // if true, external buffers were injected with sg_buffer_desc.gl_buffers - } gl; -} _sg_gl_buffer_t; -typedef _sg_gl_buffer_t _sg_buffer_t; - -typedef struct { - _sg_slot_t slot; - _sg_image_common_t cmn; - struct { - GLenum target; - GLuint msaa_render_buffer; - GLuint tex[SG_NUM_INFLIGHT_FRAMES]; - bool injected; // if true, external textures were injected with sg_image_desc.gl_textures - } gl; -} _sg_gl_image_t; -typedef _sg_gl_image_t _sg_image_t; - -typedef struct { - _sg_slot_t slot; - _sg_sampler_common_t cmn; - struct { - GLuint smp; - bool injected; // true if external sampler was injects in sg_sampler_desc.gl_sampler - } gl; -} _sg_gl_sampler_t; -typedef _sg_gl_sampler_t _sg_sampler_t; - -typedef struct { - GLint gl_loc; - sg_uniform_type type; - uint16_t count; - uint16_t offset; -} _sg_gl_uniform_t; - -typedef struct { - int num_uniforms; - _sg_gl_uniform_t uniforms[SG_MAX_UB_MEMBERS]; -} _sg_gl_uniform_block_t; - -typedef struct { - int gl_tex_slot; -} _sg_gl_shader_image_sampler_t; - -typedef struct { - _sg_str_t name; -} _sg_gl_shader_attr_t; - -typedef struct { - _sg_gl_uniform_block_t uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; - _sg_gl_shader_image_sampler_t image_samplers[SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]; -} _sg_gl_shader_stage_t; - -typedef struct { - _sg_slot_t slot; - _sg_shader_common_t cmn; - struct { - GLuint prog; - _sg_gl_shader_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; - _sg_gl_shader_stage_t stage[SG_NUM_SHADER_STAGES]; - } gl; -} _sg_gl_shader_t; -typedef _sg_gl_shader_t _sg_shader_t; - -typedef struct { - int8_t vb_index; // -1 if attr is not enabled - int8_t divisor; // -1 if not initialized - uint8_t stride; - uint8_t size; - uint8_t normalized; - int offset; - GLenum type; -} _sg_gl_attr_t; - -typedef struct { - _sg_slot_t slot; - _sg_pipeline_common_t cmn; - _sg_shader_t* shader; - struct { - _sg_gl_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; - sg_depth_state depth; - sg_stencil_state stencil; - sg_primitive_type primitive_type; - sg_blend_state blend; - sg_color_mask color_write_mask[SG_MAX_COLOR_ATTACHMENTS]; - sg_cull_mode cull_mode; - sg_face_winding face_winding; - int sample_count; - bool alpha_to_coverage_enabled; - } gl; -} _sg_gl_pipeline_t; -typedef _sg_gl_pipeline_t _sg_pipeline_t; - -typedef struct { - _sg_image_t* image; -} _sg_gl_attachment_t; - -typedef struct { - _sg_slot_t slot; - _sg_attachments_common_t cmn; - struct { - GLuint fb; - _sg_gl_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; - _sg_gl_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; - _sg_gl_attachment_t depth_stencil; - GLuint msaa_resolve_framebuffer[SG_MAX_COLOR_ATTACHMENTS]; - } gl; -} _sg_gl_attachments_t; -typedef _sg_gl_attachments_t _sg_attachments_t; - -typedef struct { - _sg_gl_attr_t gl_attr; - GLuint gl_vbuf; -} _sg_gl_cache_attr_t; - -typedef struct { - GLenum target; - GLuint texture; - GLuint sampler; -} _sg_gl_cache_texture_sampler_bind_slot; - -typedef struct { - sg_depth_state depth; - sg_stencil_state stencil; - sg_blend_state blend; - sg_color_mask color_write_mask[SG_MAX_COLOR_ATTACHMENTS]; - sg_cull_mode cull_mode; - sg_face_winding face_winding; - bool polygon_offset_enabled; - int sample_count; - sg_color blend_color; - bool alpha_to_coverage_enabled; - _sg_gl_cache_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; - GLuint vertex_buffer; - GLuint index_buffer; - GLuint storage_buffer; // general bind point - GLuint stage_storage_buffers[SG_NUM_SHADER_STAGES][SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; - GLuint stored_vertex_buffer; - GLuint stored_index_buffer; - GLuint stored_storage_buffer; - GLuint prog; - _sg_gl_cache_texture_sampler_bind_slot texture_samplers[_SG_GL_TEXTURE_SAMPLER_CACHE_SIZE]; - _sg_gl_cache_texture_sampler_bind_slot stored_texture_sampler; - int cur_ib_offset; - GLenum cur_primitive_type; - GLenum cur_index_type; - GLenum cur_active_texture; - _sg_pipeline_t* cur_pipeline; - sg_pipeline cur_pipeline_id; -} _sg_gl_state_cache_t; - -typedef struct { - bool valid; - GLuint vao; - _sg_gl_state_cache_t cache; - bool ext_anisotropic; - GLint max_anisotropy; - sg_store_action color_store_actions[SG_MAX_COLOR_ATTACHMENTS]; - sg_store_action depth_store_action; - sg_store_action stencil_store_action; - #if _SOKOL_USE_WIN32_GL_LOADER - HINSTANCE opengl32_dll; - #endif -} _sg_gl_backend_t; - -#elif defined(SOKOL_D3D11) - -typedef struct { - _sg_slot_t slot; - _sg_buffer_common_t cmn; - struct { - ID3D11Buffer* buf; - ID3D11ShaderResourceView* srv; - } d3d11; -} _sg_d3d11_buffer_t; -typedef _sg_d3d11_buffer_t _sg_buffer_t; - -typedef struct { - _sg_slot_t slot; - _sg_image_common_t cmn; - struct { - DXGI_FORMAT format; - ID3D11Texture2D* tex2d; - ID3D11Texture3D* tex3d; - ID3D11Resource* res; // either tex2d or tex3d - ID3D11ShaderResourceView* srv; - } d3d11; -} _sg_d3d11_image_t; -typedef _sg_d3d11_image_t _sg_image_t; - -typedef struct { - _sg_slot_t slot; - _sg_sampler_common_t cmn; - struct { - ID3D11SamplerState* smp; - } d3d11; -} _sg_d3d11_sampler_t; -typedef _sg_d3d11_sampler_t _sg_sampler_t; - -typedef struct { - _sg_str_t sem_name; - int sem_index; -} _sg_d3d11_shader_attr_t; - -typedef struct { - ID3D11Buffer* cbufs[SG_MAX_SHADERSTAGE_UBS]; -} _sg_d3d11_shader_stage_t; - -typedef struct { - _sg_slot_t slot; - _sg_shader_common_t cmn; - struct { - _sg_d3d11_shader_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; - _sg_d3d11_shader_stage_t stage[SG_NUM_SHADER_STAGES]; - ID3D11VertexShader* vs; - ID3D11PixelShader* fs; - void* vs_blob; - size_t vs_blob_length; - } d3d11; -} _sg_d3d11_shader_t; -typedef _sg_d3d11_shader_t _sg_shader_t; - -typedef struct { - _sg_slot_t slot; - _sg_pipeline_common_t cmn; - _sg_shader_t* shader; - struct { - UINT stencil_ref; - UINT vb_strides[SG_MAX_VERTEX_BUFFERS]; - D3D_PRIMITIVE_TOPOLOGY topology; - DXGI_FORMAT index_format; - ID3D11InputLayout* il; - ID3D11RasterizerState* rs; - ID3D11DepthStencilState* dss; - ID3D11BlendState* bs; - } d3d11; -} _sg_d3d11_pipeline_t; -typedef _sg_d3d11_pipeline_t _sg_pipeline_t; - -typedef struct { - _sg_image_t* image; - union { - ID3D11RenderTargetView* rtv; - ID3D11DepthStencilView* dsv; - } view; -} _sg_d3d11_attachment_t; - -typedef struct { - _sg_slot_t slot; - _sg_attachments_common_t cmn; - struct { - _sg_d3d11_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; - _sg_d3d11_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; - _sg_d3d11_attachment_t depth_stencil; - } d3d11; -} _sg_d3d11_attachments_t; -typedef _sg_d3d11_attachments_t _sg_attachments_t; - -typedef struct { - bool valid; - ID3D11Device* dev; - ID3D11DeviceContext* ctx; - bool use_indexed_draw; - bool use_instanced_draw; - _sg_pipeline_t* cur_pipeline; - sg_pipeline cur_pipeline_id; - struct { - ID3D11RenderTargetView* render_view; - ID3D11RenderTargetView* resolve_view; - } cur_pass; - // on-demand loaded d3dcompiler_47.dll handles - HINSTANCE d3dcompiler_dll; - bool d3dcompiler_dll_load_failed; - pD3DCompile D3DCompile_func; - // global subresourcedata array for texture updates - D3D11_SUBRESOURCE_DATA subres_data[SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS]; -} _sg_d3d11_backend_t; - -#elif defined(SOKOL_METAL) - -#if defined(_SG_TARGET_MACOS) || defined(_SG_TARGET_IOS_SIMULATOR) -#define _SG_MTL_UB_ALIGN (256) -#else -#define _SG_MTL_UB_ALIGN (16) -#endif -#define _SG_MTL_INVALID_SLOT_INDEX (0) - -typedef struct { - uint32_t frame_index; // frame index at which it is safe to release this resource - int slot_index; -} _sg_mtl_release_item_t; - -typedef struct { - NSMutableArray* pool; - int num_slots; - int free_queue_top; - int* free_queue; - int release_queue_front; - int release_queue_back; - _sg_mtl_release_item_t* release_queue; -} _sg_mtl_idpool_t; - -typedef struct { - _sg_slot_t slot; - _sg_buffer_common_t cmn; - struct { - int buf[SG_NUM_INFLIGHT_FRAMES]; // index into _sg_mtl_pool - } mtl; -} _sg_mtl_buffer_t; -typedef _sg_mtl_buffer_t _sg_buffer_t; - -typedef struct { - _sg_slot_t slot; - _sg_image_common_t cmn; - struct { - int tex[SG_NUM_INFLIGHT_FRAMES]; - } mtl; -} _sg_mtl_image_t; -typedef _sg_mtl_image_t _sg_image_t; - -typedef struct { - _sg_slot_t slot; - _sg_sampler_common_t cmn; - struct { - int sampler_state; - } mtl; -} _sg_mtl_sampler_t; -typedef _sg_mtl_sampler_t _sg_sampler_t; - -typedef struct { - int mtl_lib; - int mtl_func; -} _sg_mtl_shader_stage_t; - -typedef struct { - _sg_slot_t slot; - _sg_shader_common_t cmn; - struct { - _sg_mtl_shader_stage_t stage[SG_NUM_SHADER_STAGES]; - } mtl; -} _sg_mtl_shader_t; -typedef _sg_mtl_shader_t _sg_shader_t; - -typedef struct { - _sg_slot_t slot; - _sg_pipeline_common_t cmn; - _sg_shader_t* shader; - struct { - MTLPrimitiveType prim_type; - int index_size; - MTLIndexType index_type; - MTLCullMode cull_mode; - MTLWinding winding; - uint32_t stencil_ref; - int rps; - int dss; - } mtl; -} _sg_mtl_pipeline_t; -typedef _sg_mtl_pipeline_t _sg_pipeline_t; - -typedef struct { - _sg_image_t* image; -} _sg_mtl_attachment_t; - -typedef struct { - _sg_slot_t slot; - _sg_attachments_common_t cmn; - struct { - _sg_mtl_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; - _sg_mtl_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; - _sg_mtl_attachment_t depth_stencil; - } mtl; -} _sg_mtl_attachments_t; -typedef _sg_mtl_attachments_t _sg_attachments_t; - -// resource binding state cache -typedef struct { - const _sg_pipeline_t* cur_pipeline; - sg_pipeline cur_pipeline_id; - const _sg_buffer_t* cur_indexbuffer; - sg_buffer cur_indexbuffer_id; - int cur_indexbuffer_offset; - int cur_vertexbuffer_offsets[SG_MAX_VERTEX_BUFFERS]; - sg_buffer cur_vertexbuffer_ids[SG_MAX_VERTEX_BUFFERS]; - sg_image cur_vs_image_ids[SG_MAX_SHADERSTAGE_IMAGES]; - sg_image cur_fs_image_ids[SG_MAX_SHADERSTAGE_IMAGES]; - sg_sampler cur_vs_sampler_ids[SG_MAX_SHADERSTAGE_SAMPLERS]; - sg_sampler cur_fs_sampler_ids[SG_MAX_SHADERSTAGE_SAMPLERS]; - sg_buffer cur_vs_storagebuffer_ids[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; - sg_buffer cur_fs_storagebuffer_ids[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; -} _sg_mtl_state_cache_t; - -typedef struct { - bool valid; - bool use_shared_storage_mode; - uint32_t cur_frame_rotate_index; - int ub_size; - int cur_ub_offset; - uint8_t* cur_ub_base_ptr; - _sg_mtl_state_cache_t state_cache; - _sg_mtl_idpool_t idpool; - dispatch_semaphore_t sem; - id device; - id cmd_queue; - id cmd_buffer; - id cmd_encoder; - id cur_drawable; - id uniform_buffers[SG_NUM_INFLIGHT_FRAMES]; -} _sg_mtl_backend_t; - -#elif defined(SOKOL_WGPU) - -#define _SG_WGPU_ROWPITCH_ALIGN (256) -#define _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE (1<<16) // also see WGPULimits.maxUniformBufferBindingSize -#define _SG_WGPU_NUM_BINDGROUPS (2) // 0: uniforms, 1: images and sampler on both shader stages -#define _SG_WGPU_UNIFORM_BINDGROUP_INDEX (0) -#define _SG_WGPU_IMAGE_SAMPLER_BINDGROUP_INDEX (1) -#define _SG_WGPU_MAX_BINDGROUP_ENTRIES (SG_NUM_SHADER_STAGES * (SG_MAX_SHADERSTAGE_IMAGES + SG_MAX_SHADERSTAGE_SAMPLERS + SG_MAX_SHADERSTAGE_STORAGEBUFFERS)) - -typedef struct { - _sg_slot_t slot; - _sg_buffer_common_t cmn; - struct { - WGPUBuffer buf; - } wgpu; -} _sg_wgpu_buffer_t; -typedef _sg_wgpu_buffer_t _sg_buffer_t; - -typedef struct { - _sg_slot_t slot; - _sg_image_common_t cmn; - struct { - WGPUTexture tex; - WGPUTextureView view; - } wgpu; -} _sg_wgpu_image_t; -typedef _sg_wgpu_image_t _sg_image_t; - -typedef struct { - _sg_slot_t slot; - _sg_sampler_common_t cmn; - struct { - WGPUSampler smp; - } wgpu; -} _sg_wgpu_sampler_t; -typedef _sg_wgpu_sampler_t _sg_sampler_t; - -typedef struct { - WGPUShaderModule module; - _sg_str_t entry; -} _sg_wgpu_shader_stage_t; - -typedef struct { - _sg_slot_t slot; - _sg_shader_common_t cmn; - struct { - _sg_wgpu_shader_stage_t stage[SG_NUM_SHADER_STAGES]; - WGPUBindGroupLayout bind_group_layout; - } wgpu; -} _sg_wgpu_shader_t; -typedef _sg_wgpu_shader_t _sg_shader_t; - -typedef struct { - _sg_slot_t slot; - _sg_pipeline_common_t cmn; - _sg_shader_t* shader; - struct { - WGPURenderPipeline pip; - WGPUColor blend_color; - } wgpu; -} _sg_wgpu_pipeline_t; -typedef _sg_wgpu_pipeline_t _sg_pipeline_t; - -typedef struct { - _sg_image_t* image; - WGPUTextureView view; -} _sg_wgpu_attachment_t; - -typedef struct { - _sg_slot_t slot; - _sg_attachments_common_t cmn; - struct { - _sg_wgpu_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; - _sg_wgpu_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; - _sg_wgpu_attachment_t depth_stencil; - } wgpu; -} _sg_wgpu_attachments_t; -typedef _sg_wgpu_attachments_t _sg_attachments_t; - -// a pool of per-frame uniform buffers -typedef struct { - uint32_t num_bytes; - uint32_t offset; // current offset into buf - uint8_t* staging; // intermediate buffer for uniform data updates - WGPUBuffer buf; // the GPU-side uniform buffer - struct { - WGPUBindGroupLayout group_layout; - WGPUBindGroup group; - uint32_t offsets[SG_NUM_SHADER_STAGES][SG_MAX_SHADERSTAGE_UBS]; - } bind; -} _sg_wgpu_uniform_buffer_t; - -typedef struct { - uint32_t id; -} _sg_wgpu_bindgroup_handle_t; - -typedef enum { - _SG_WGPU_BINDGROUPSCACHEITEMTYPE_NONE = 0, - _SG_WGPU_BINDGROUPSCACHEITEMTYPE_IMAGE = 0x1111111111111111, - _SG_WGPU_BINDGROUPSCACHEITEMTYPE_SAMPLER = 0x2222222222222222, - _SG_WGPU_BINDGROUPSCACHEITEMTYPE_STORAGEBUFFER = 0x3333333333333333, - _SG_WGPU_BINDGROUPSCACHEITEMTYPE_PIPELINE = 0x4444444444444444, -} _sg_wgpu_bindgroups_cache_item_type_t; - -#define _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS (1 + _SG_WGPU_MAX_BINDGROUP_ENTRIES) -typedef struct { - uint64_t hash; - // the format of cache key items is (_sg_wgpu_bindgroups_cache_item_type_t << 32) | handle.id, - // where the item type is a per-resource-type bit pattern - uint64_t items[_SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS]; -} _sg_wgpu_bindgroups_cache_key_t; - -typedef struct { - uint32_t num; // must be 2^n - uint32_t index_mask; // mask to turn hash into valid index - _sg_wgpu_bindgroup_handle_t* items; -} _sg_wgpu_bindgroups_cache_t; - -typedef struct { - _sg_slot_t slot; - WGPUBindGroup bindgroup; - _sg_wgpu_bindgroups_cache_key_t key; -} _sg_wgpu_bindgroup_t; - -typedef struct { - _sg_pool_t pool; - _sg_wgpu_bindgroup_t* bindgroups; -} _sg_wgpu_bindgroups_pool_t; - -typedef struct { - struct { - sg_buffer buffer; - int offset; - } vbs[SG_MAX_VERTEX_BUFFERS]; - struct { - sg_buffer buffer; - int offset; - } ib; - _sg_wgpu_bindgroup_handle_t bg; -} _sg_wgpu_bindings_cache_t; - -// the WGPU backend state -typedef struct { - bool valid; - bool use_indexed_draw; - WGPUDevice dev; - WGPUSupportedLimits limits; - WGPUQueue queue; - WGPUCommandEncoder cmd_enc; - WGPURenderPassEncoder pass_enc; - WGPUBindGroup empty_bind_group; - const _sg_pipeline_t* cur_pipeline; - sg_pipeline cur_pipeline_id; - _sg_wgpu_uniform_buffer_t uniform; - _sg_wgpu_bindings_cache_t bindings_cache; - _sg_wgpu_bindgroups_cache_t bindgroups_cache; - _sg_wgpu_bindgroups_pool_t bindgroups_pool; -} _sg_wgpu_backend_t; -#endif - -// POOL STRUCTS - -// this *MUST* remain 0 -#define _SG_INVALID_SLOT_INDEX (0) - -typedef struct { - _sg_pool_t buffer_pool; - _sg_pool_t image_pool; - _sg_pool_t sampler_pool; - _sg_pool_t shader_pool; - _sg_pool_t pipeline_pool; - _sg_pool_t attachments_pool; - _sg_buffer_t* buffers; - _sg_image_t* images; - _sg_sampler_t* samplers; - _sg_shader_t* shaders; - _sg_pipeline_t* pipelines; - _sg_attachments_t* attachments; -} _sg_pools_t; - -typedef struct { - int num; // number of allocated commit listener items - int upper; // the current upper index (no valid items past this point) - sg_commit_listener* items; -} _sg_commit_listeners_t; - -// resolved resource bindings struct -typedef struct { - _sg_pipeline_t* pip; - int num_vbs; - int num_vs_imgs; - int num_vs_smps; - int num_vs_sbufs; - int num_fs_imgs; - int num_fs_smps; - int num_fs_sbufs; - int vb_offsets[SG_MAX_VERTEX_BUFFERS]; - int ib_offset; - _sg_buffer_t* vbs[SG_MAX_VERTEX_BUFFERS]; - _sg_buffer_t* ib; - _sg_image_t* vs_imgs[SG_MAX_SHADERSTAGE_IMAGES]; - _sg_sampler_t* vs_smps[SG_MAX_SHADERSTAGE_SAMPLERS]; - _sg_buffer_t* vs_sbufs[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; - _sg_image_t* fs_imgs[SG_MAX_SHADERSTAGE_IMAGES]; - _sg_sampler_t* fs_smps[SG_MAX_SHADERSTAGE_SAMPLERS]; - _sg_buffer_t* fs_sbufs[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; -} _sg_bindings_t; - -typedef struct { - bool sample; - bool filter; - bool render; - bool blend; - bool msaa; - bool depth; -} _sg_pixelformat_info_t; - -typedef struct { - bool valid; - sg_desc desc; // original desc with default values patched in - uint32_t frame_index; - struct { - bool valid; - bool in_pass; - sg_attachments atts_id; // SG_INVALID_ID in a swapchain pass - _sg_attachments_t* atts; // 0 in a swapchain pass - int width; - int height; - struct { - sg_pixel_format color_fmt; - sg_pixel_format depth_fmt; - int sample_count; - } swapchain; - } cur_pass; - sg_pipeline cur_pipeline; - bool next_draw_valid; - #if defined(SOKOL_DEBUG) - sg_log_item validate_error; - #endif - _sg_pools_t pools; - sg_backend backend; - sg_features features; - sg_limits limits; - _sg_pixelformat_info_t formats[_SG_PIXELFORMAT_NUM]; - bool stats_enabled; - sg_frame_stats stats; - sg_frame_stats prev_stats; - #if defined(_SOKOL_ANY_GL) - _sg_gl_backend_t gl; - #elif defined(SOKOL_METAL) - _sg_mtl_backend_t mtl; - #elif defined(SOKOL_D3D11) - _sg_d3d11_backend_t d3d11; - #elif defined(SOKOL_WGPU) - _sg_wgpu_backend_t wgpu; - #endif - #if defined(SOKOL_TRACE_HOOKS) - sg_trace_hooks hooks; - #endif - _sg_commit_listeners_t commit_listeners; -} _sg_state_t; -static _sg_state_t _sg; - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SG_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _sg_log_messages[] = { - _SG_LOG_ITEMS -}; -#undef _SG_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SG_PANIC(code) _sg_log(SG_LOGITEM_ ##code, 0, 0, __LINE__) -#define _SG_ERROR(code) _sg_log(SG_LOGITEM_ ##code, 1, 0, __LINE__) -#define _SG_WARN(code) _sg_log(SG_LOGITEM_ ##code, 2, 0, __LINE__) -#define _SG_INFO(code) _sg_log(SG_LOGITEM_ ##code, 3, 0, __LINE__) -#define _SG_LOGMSG(code,msg) _sg_log(SG_LOGITEM_ ##code, 3, msg, __LINE__) -#define _SG_VALIDATE(cond,code) if (!(cond)){ _sg.validate_error = SG_LOGITEM_ ##code; _sg_log(SG_LOGITEM_ ##code, 1, 0, __LINE__); } - -static void _sg_log(sg_log_item log_item, uint32_t log_level, const char* msg, uint32_t line_nr) { - if (_sg.desc.logger.func) { - const char* filename = 0; - #if defined(SOKOL_DEBUG) - filename = __FILE__; - if (0 == msg) { - msg = _sg_log_messages[log_item]; - } - #endif - _sg.desc.logger.func("sg", log_level, log_item, msg, line_nr, filename, _sg.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory - -// a helper macro to clear a struct with potentially ARC'ed ObjC references -#if defined(SOKOL_METAL) - #if defined(__cplusplus) - #define _SG_CLEAR_ARC_STRUCT(type, item) { item = type(); } - #else - #define _SG_CLEAR_ARC_STRUCT(type, item) { item = (type) { 0 }; } - #endif -#else - #define _SG_CLEAR_ARC_STRUCT(type, item) { _sg_clear(&item, sizeof(item)); } -#endif - -_SOKOL_PRIVATE void _sg_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -_SOKOL_PRIVATE void* _sg_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_sg.desc.allocator.alloc_fn) { - ptr = _sg.desc.allocator.alloc_fn(size, _sg.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SG_PANIC(MALLOC_FAILED); - } - return ptr; -} - -_SOKOL_PRIVATE void* _sg_malloc_clear(size_t size) { - void* ptr = _sg_malloc(size); - _sg_clear(ptr, size); - return ptr; -} - -_SOKOL_PRIVATE void _sg_free(void* ptr) { - if (_sg.desc.allocator.free_fn) { - _sg.desc.allocator.free_fn(ptr, _sg.desc.allocator.user_data); - } else { - free(ptr); - } -} - -_SOKOL_PRIVATE bool _sg_strempty(const _sg_str_t* str) { - return 0 == str->buf[0]; -} - -_SOKOL_PRIVATE const char* _sg_strptr(const _sg_str_t* str) { - return &str->buf[0]; -} - -_SOKOL_PRIVATE void _sg_strcpy(_sg_str_t* dst, const char* src) { - SOKOL_ASSERT(dst); - if (src) { - #if defined(_MSC_VER) - strncpy_s(dst->buf, _SG_STRING_SIZE, src, (_SG_STRING_SIZE-1)); - #else - strncpy(dst->buf, src, _SG_STRING_SIZE); - #endif - dst->buf[_SG_STRING_SIZE-1] = 0; - } else { - _sg_clear(dst->buf, _SG_STRING_SIZE); - } -} - -// ██ ██ ███████ ██ ██████ ███████ ██████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ █████ ██ ██████ █████ ██████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ███████ ██ ███████ ██ ██ ███████ -// -// >>helpers -_SOKOL_PRIVATE uint32_t _sg_align_u32(uint32_t val, uint32_t align) { - SOKOL_ASSERT((align > 0) && ((align & (align - 1)) == 0)); - return (val + (align - 1)) & ~(align - 1); -} - -typedef struct { int x, y, w, h; } _sg_recti_t; - -_SOKOL_PRIVATE _sg_recti_t _sg_clipi(int x, int y, int w, int h, int clip_width, int clip_height) { - x = _sg_min(_sg_max(0, x), clip_width-1); - y = _sg_min(_sg_max(0, y), clip_height-1); - if ((x + w) > clip_width) { - w = clip_width - x; - } - if ((y + h) > clip_height) { - h = clip_height - y; - } - w = _sg_max(w, 1); - h = _sg_max(h, 1); - const _sg_recti_t res = { x, y, w, h }; - return res; -} - -_SOKOL_PRIVATE int _sg_vertexformat_bytesize(sg_vertex_format fmt) { - switch (fmt) { - case SG_VERTEXFORMAT_FLOAT: return 4; - case SG_VERTEXFORMAT_FLOAT2: return 8; - case SG_VERTEXFORMAT_FLOAT3: return 12; - case SG_VERTEXFORMAT_FLOAT4: return 16; - case SG_VERTEXFORMAT_BYTE4: return 4; - case SG_VERTEXFORMAT_BYTE4N: return 4; - case SG_VERTEXFORMAT_UBYTE4: return 4; - case SG_VERTEXFORMAT_UBYTE4N: return 4; - case SG_VERTEXFORMAT_SHORT2: return 4; - case SG_VERTEXFORMAT_SHORT2N: return 4; - case SG_VERTEXFORMAT_USHORT2N: return 4; - case SG_VERTEXFORMAT_SHORT4: return 8; - case SG_VERTEXFORMAT_SHORT4N: return 8; - case SG_VERTEXFORMAT_USHORT4N: return 8; - case SG_VERTEXFORMAT_UINT10_N2: return 4; - case SG_VERTEXFORMAT_HALF2: return 4; - case SG_VERTEXFORMAT_HALF4: return 8; - case SG_VERTEXFORMAT_INVALID: return 0; - default: - SOKOL_UNREACHABLE; - return -1; - } -} - -_SOKOL_PRIVATE uint32_t _sg_uniform_alignment(sg_uniform_type type, int array_count, sg_uniform_layout ub_layout) { - if (ub_layout == SG_UNIFORMLAYOUT_NATIVE) { - return 1; - } else { - SOKOL_ASSERT(array_count > 0); - if (array_count == 1) { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_INT: - return 4; - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_INT2: - return 8; - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT3: - case SG_UNIFORMTYPE_INT4: - return 16; - case SG_UNIFORMTYPE_MAT4: - return 16; - default: - SOKOL_UNREACHABLE; - return 1; - } - } else { - return 16; - } - } -} - -_SOKOL_PRIVATE uint32_t _sg_uniform_size(sg_uniform_type type, int array_count, sg_uniform_layout ub_layout) { - SOKOL_ASSERT(array_count > 0); - if (array_count == 1) { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_INT: - return 4; - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_INT2: - return 8; - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_INT3: - return 12; - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT4: - return 16; - case SG_UNIFORMTYPE_MAT4: - return 64; - default: - SOKOL_UNREACHABLE; - return 0; - } - } else { - if (ub_layout == SG_UNIFORMLAYOUT_NATIVE) { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_INT: - return 4 * (uint32_t)array_count; - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_INT2: - return 8 * (uint32_t)array_count; - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_INT3: - return 12 * (uint32_t)array_count; - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT4: - return 16 * (uint32_t)array_count; - case SG_UNIFORMTYPE_MAT4: - return 64 * (uint32_t)array_count; - default: - SOKOL_UNREACHABLE; - return 0; - } - } else { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT: - case SG_UNIFORMTYPE_INT2: - case SG_UNIFORMTYPE_INT3: - case SG_UNIFORMTYPE_INT4: - return 16 * (uint32_t)array_count; - case SG_UNIFORMTYPE_MAT4: - return 64 * (uint32_t)array_count; - default: - SOKOL_UNREACHABLE; - return 0; - } - } - } -} - -_SOKOL_PRIVATE bool _sg_is_compressed_pixel_format(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_BC1_RGBA: - case SG_PIXELFORMAT_BC2_RGBA: - case SG_PIXELFORMAT_BC3_RGBA: - case SG_PIXELFORMAT_BC3_SRGBA: - case SG_PIXELFORMAT_BC4_R: - case SG_PIXELFORMAT_BC4_RSN: - case SG_PIXELFORMAT_BC5_RG: - case SG_PIXELFORMAT_BC5_RGSN: - case SG_PIXELFORMAT_BC6H_RGBF: - case SG_PIXELFORMAT_BC6H_RGBUF: - case SG_PIXELFORMAT_BC7_RGBA: - case SG_PIXELFORMAT_BC7_SRGBA: - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: - case SG_PIXELFORMAT_ETC2_RGB8: - case SG_PIXELFORMAT_ETC2_SRGB8: - case SG_PIXELFORMAT_ETC2_RGB8A1: - case SG_PIXELFORMAT_ETC2_RGBA8: - case SG_PIXELFORMAT_ETC2_SRGB8A8: - case SG_PIXELFORMAT_EAC_R11: - case SG_PIXELFORMAT_EAC_R11SN: - case SG_PIXELFORMAT_EAC_RG11: - case SG_PIXELFORMAT_EAC_RG11SN: - case SG_PIXELFORMAT_ASTC_4x4_RGBA: - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: - return true; - default: - return false; - } -} - -_SOKOL_PRIVATE bool _sg_is_valid_rendertarget_color_format(sg_pixel_format fmt) { - const int fmt_index = (int) fmt; - SOKOL_ASSERT((fmt_index >= 0) && (fmt_index < _SG_PIXELFORMAT_NUM)); - return _sg.formats[fmt_index].render && !_sg.formats[fmt_index].depth; -} - -_SOKOL_PRIVATE bool _sg_is_valid_rendertarget_depth_format(sg_pixel_format fmt) { - const int fmt_index = (int) fmt; - SOKOL_ASSERT((fmt_index >= 0) && (fmt_index < _SG_PIXELFORMAT_NUM)); - return _sg.formats[fmt_index].render && _sg.formats[fmt_index].depth; -} - -_SOKOL_PRIVATE bool _sg_is_depth_or_depth_stencil_format(sg_pixel_format fmt) { - return (SG_PIXELFORMAT_DEPTH == fmt) || (SG_PIXELFORMAT_DEPTH_STENCIL == fmt); -} - -_SOKOL_PRIVATE bool _sg_is_depth_stencil_format(sg_pixel_format fmt) { - return (SG_PIXELFORMAT_DEPTH_STENCIL == fmt); -} - -_SOKOL_PRIVATE int _sg_pixelformat_bytesize(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_R8: - case SG_PIXELFORMAT_R8SN: - case SG_PIXELFORMAT_R8UI: - case SG_PIXELFORMAT_R8SI: - return 1; - case SG_PIXELFORMAT_R16: - case SG_PIXELFORMAT_R16SN: - case SG_PIXELFORMAT_R16UI: - case SG_PIXELFORMAT_R16SI: - case SG_PIXELFORMAT_R16F: - case SG_PIXELFORMAT_RG8: - case SG_PIXELFORMAT_RG8SN: - case SG_PIXELFORMAT_RG8UI: - case SG_PIXELFORMAT_RG8SI: - return 2; - case SG_PIXELFORMAT_R32UI: - case SG_PIXELFORMAT_R32SI: - case SG_PIXELFORMAT_R32F: - case SG_PIXELFORMAT_RG16: - case SG_PIXELFORMAT_RG16SN: - case SG_PIXELFORMAT_RG16UI: - case SG_PIXELFORMAT_RG16SI: - case SG_PIXELFORMAT_RG16F: - case SG_PIXELFORMAT_RGBA8: - case SG_PIXELFORMAT_SRGB8A8: - case SG_PIXELFORMAT_RGBA8SN: - case SG_PIXELFORMAT_RGBA8UI: - case SG_PIXELFORMAT_RGBA8SI: - case SG_PIXELFORMAT_BGRA8: - case SG_PIXELFORMAT_RGB10A2: - case SG_PIXELFORMAT_RG11B10F: - case SG_PIXELFORMAT_RGB9E5: - return 4; - case SG_PIXELFORMAT_RG32UI: - case SG_PIXELFORMAT_RG32SI: - case SG_PIXELFORMAT_RG32F: - case SG_PIXELFORMAT_RGBA16: - case SG_PIXELFORMAT_RGBA16SN: - case SG_PIXELFORMAT_RGBA16UI: - case SG_PIXELFORMAT_RGBA16SI: - case SG_PIXELFORMAT_RGBA16F: - return 8; - case SG_PIXELFORMAT_RGBA32UI: - case SG_PIXELFORMAT_RGBA32SI: - case SG_PIXELFORMAT_RGBA32F: - return 16; - case SG_PIXELFORMAT_DEPTH: - case SG_PIXELFORMAT_DEPTH_STENCIL: - return 4; - default: - SOKOL_UNREACHABLE; - return 0; - } -} - -_SOKOL_PRIVATE int _sg_roundup(int val, int round_to) { - return (val+(round_to-1)) & ~(round_to-1); -} - -_SOKOL_PRIVATE uint32_t _sg_roundup_u32(uint32_t val, uint32_t round_to) { - return (val+(round_to-1)) & ~(round_to-1); -} - -_SOKOL_PRIVATE uint64_t _sg_roundup_u64(uint64_t val, uint64_t round_to) { - return (val+(round_to-1)) & ~(round_to-1); -} - -_SOKOL_PRIVATE bool _sg_multiple_u64(uint64_t val, uint64_t of) { - return (val & (of-1)) == 0; -} - -/* return row pitch for an image - - see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp - - For the special PVRTC pitch computation, see: - GL extension requirement (https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt) - - Quote: - - 6) How is the imageSize argument calculated for the CompressedTexImage2D - and CompressedTexSubImage2D functions. - - Resolution: For PVRTC 4BPP formats the imageSize is calculated as: - ( max(width, 8) * max(height, 8) * 4 + 7) / 8 - For PVRTC 2BPP formats the imageSize is calculated as: - ( max(width, 16) * max(height, 8) * 2 + 7) / 8 -*/ -_SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) { - int pitch; - switch (fmt) { - case SG_PIXELFORMAT_BC1_RGBA: - case SG_PIXELFORMAT_BC4_R: - case SG_PIXELFORMAT_BC4_RSN: - case SG_PIXELFORMAT_ETC2_RGB8: - case SG_PIXELFORMAT_ETC2_SRGB8: - case SG_PIXELFORMAT_ETC2_RGB8A1: - case SG_PIXELFORMAT_EAC_R11: - case SG_PIXELFORMAT_EAC_R11SN: - pitch = ((width + 3) / 4) * 8; - pitch = pitch < 8 ? 8 : pitch; - break; - case SG_PIXELFORMAT_BC2_RGBA: - case SG_PIXELFORMAT_BC3_RGBA: - case SG_PIXELFORMAT_BC3_SRGBA: - case SG_PIXELFORMAT_BC5_RG: - case SG_PIXELFORMAT_BC5_RGSN: - case SG_PIXELFORMAT_BC6H_RGBF: - case SG_PIXELFORMAT_BC6H_RGBUF: - case SG_PIXELFORMAT_BC7_RGBA: - case SG_PIXELFORMAT_BC7_SRGBA: - case SG_PIXELFORMAT_ETC2_RGBA8: - case SG_PIXELFORMAT_ETC2_SRGB8A8: - case SG_PIXELFORMAT_EAC_RG11: - case SG_PIXELFORMAT_EAC_RG11SN: - case SG_PIXELFORMAT_ASTC_4x4_RGBA: - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: - pitch = ((width + 3) / 4) * 16; - pitch = pitch < 16 ? 16 : pitch; - break; - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: - pitch = (_sg_max(width, 8) * 4 + 7) / 8; - break; - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: - pitch = (_sg_max(width, 16) * 2 + 7) / 8; - break; - default: - pitch = width * _sg_pixelformat_bytesize(fmt); - break; - } - pitch = _sg_roundup(pitch, row_align); - return pitch; -} - -// compute the number of rows in a surface depending on pixel format -_SOKOL_PRIVATE int _sg_num_rows(sg_pixel_format fmt, int height) { - int num_rows; - switch (fmt) { - case SG_PIXELFORMAT_BC1_RGBA: - case SG_PIXELFORMAT_BC4_R: - case SG_PIXELFORMAT_BC4_RSN: - case SG_PIXELFORMAT_ETC2_RGB8: - case SG_PIXELFORMAT_ETC2_SRGB8: - case SG_PIXELFORMAT_ETC2_RGB8A1: - case SG_PIXELFORMAT_ETC2_RGBA8: - case SG_PIXELFORMAT_ETC2_SRGB8A8: - case SG_PIXELFORMAT_EAC_R11: - case SG_PIXELFORMAT_EAC_R11SN: - case SG_PIXELFORMAT_EAC_RG11: - case SG_PIXELFORMAT_EAC_RG11SN: - case SG_PIXELFORMAT_BC2_RGBA: - case SG_PIXELFORMAT_BC3_RGBA: - case SG_PIXELFORMAT_BC3_SRGBA: - case SG_PIXELFORMAT_BC5_RG: - case SG_PIXELFORMAT_BC5_RGSN: - case SG_PIXELFORMAT_BC6H_RGBF: - case SG_PIXELFORMAT_BC6H_RGBUF: - case SG_PIXELFORMAT_BC7_RGBA: - case SG_PIXELFORMAT_BC7_SRGBA: - case SG_PIXELFORMAT_ASTC_4x4_RGBA: - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: - num_rows = ((height + 3) / 4); - break; - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: - /* NOTE: this is most likely not correct because it ignores any - PVCRTC block size, but multiplied with _sg_row_pitch() - it gives the correct surface pitch. - - See: https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt - */ - num_rows = ((_sg_max(height, 8) + 7) / 8) * 8; - break; - default: - num_rows = height; - break; - } - if (num_rows < 1) { - num_rows = 1; - } - return num_rows; -} - -// return size of a mipmap level -_SOKOL_PRIVATE int _sg_miplevel_dim(int base_dim, int mip_level) { - return _sg_max(base_dim >> mip_level, 1); -} - -/* return pitch of a 2D subimage / texture slice - see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp -*/ -_SOKOL_PRIVATE int _sg_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align) { - int num_rows = _sg_num_rows(fmt, height); - return num_rows * _sg_row_pitch(fmt, width, row_align); -} - -// capability table pixel format helper functions -_SOKOL_PRIVATE void _sg_pixelformat_all(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->filter = true; - pfi->blend = true; - pfi->render = true; - pfi->msaa = true; -} - -_SOKOL_PRIVATE void _sg_pixelformat_s(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; -} - -_SOKOL_PRIVATE void _sg_pixelformat_sf(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->filter = true; -} - -_SOKOL_PRIVATE void _sg_pixelformat_sr(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->render = true; -} - -_SOKOL_PRIVATE void _sg_pixelformat_sfr(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->filter = true; - pfi->render = true; -} - -_SOKOL_PRIVATE void _sg_pixelformat_srmd(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->render = true; - pfi->msaa = true; - pfi->depth = true; -} - -_SOKOL_PRIVATE void _sg_pixelformat_srm(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->render = true; - pfi->msaa = true; -} - -_SOKOL_PRIVATE void _sg_pixelformat_sfrm(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->filter = true; - pfi->render = true; - pfi->msaa = true; -} -_SOKOL_PRIVATE void _sg_pixelformat_sbrm(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->blend = true; - pfi->render = true; - pfi->msaa = true; -} - -_SOKOL_PRIVATE void _sg_pixelformat_sbr(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->blend = true; - pfi->render = true; -} - -_SOKOL_PRIVATE void _sg_pixelformat_sfbr(_sg_pixelformat_info_t* pfi) { - pfi->sample = true; - pfi->filter = true; - pfi->blend = true; - pfi->render = true; -} - -_SOKOL_PRIVATE sg_pass_action _sg_pass_action_defaults(const sg_pass_action* action) { - SOKOL_ASSERT(action); - sg_pass_action res = *action; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (res.colors[i].load_action == _SG_LOADACTION_DEFAULT) { - res.colors[i].load_action = SG_LOADACTION_CLEAR; - res.colors[i].clear_value.r = SG_DEFAULT_CLEAR_RED; - res.colors[i].clear_value.g = SG_DEFAULT_CLEAR_GREEN; - res.colors[i].clear_value.b = SG_DEFAULT_CLEAR_BLUE; - res.colors[i].clear_value.a = SG_DEFAULT_CLEAR_ALPHA; - } - if (res.colors[i].store_action == _SG_STOREACTION_DEFAULT) { - res.colors[i].store_action = SG_STOREACTION_STORE; - } - } - if (res.depth.load_action == _SG_LOADACTION_DEFAULT) { - res.depth.load_action = SG_LOADACTION_CLEAR; - res.depth.clear_value = SG_DEFAULT_CLEAR_DEPTH; - } - if (res.depth.store_action == _SG_STOREACTION_DEFAULT) { - res.depth.store_action = SG_STOREACTION_DONTCARE; - } - if (res.stencil.load_action == _SG_LOADACTION_DEFAULT) { - res.stencil.load_action = SG_LOADACTION_CLEAR; - res.stencil.clear_value = SG_DEFAULT_CLEAR_STENCIL; - } - if (res.stencil.store_action == _SG_STOREACTION_DEFAULT) { - res.stencil.store_action = SG_STOREACTION_DONTCARE; - } - return res; -} - -// ██████ ██ ██ ███ ███ ███ ███ ██ ██ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ -// ██ ██ ██ ██ ████ ████ ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██ ██ ██ ██ ██ ████ ██ ██ ████ ██ ████ ██████ ███████ ██ █████ █████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██ ██ ██ ██ ██ ██████ ██ ██ ██████ ██ ██ ███████ ██ ████ ██████ -// -// >>dummy backend -#if defined(SOKOL_DUMMY_BACKEND) - -_SOKOL_PRIVATE void _sg_dummy_setup_backend(const sg_desc* desc) { - SOKOL_ASSERT(desc); - _SOKOL_UNUSED(desc); - _sg.backend = SG_BACKEND_DUMMY; - for (int i = SG_PIXELFORMAT_R8; i < SG_PIXELFORMAT_BC1_RGBA; i++) { - _sg.formats[i].sample = true; - _sg.formats[i].filter = true; - _sg.formats[i].render = true; - _sg.formats[i].blend = true; - _sg.formats[i].msaa = true; - } - _sg.formats[SG_PIXELFORMAT_DEPTH].depth = true; - _sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL].depth = true; -} - -_SOKOL_PRIVATE void _sg_dummy_discard_backend(void) { - // empty -} - -_SOKOL_PRIVATE void _sg_dummy_reset_state_cache(void) { - // empty -} - -_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { - SOKOL_ASSERT(buf && desc); - _SOKOL_UNUSED(buf); - _SOKOL_UNUSED(desc); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_dummy_discard_buffer(_sg_buffer_t* buf) { - SOKOL_ASSERT(buf); - _SOKOL_UNUSED(buf); -} - -_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_image(_sg_image_t* img, const sg_image_desc* desc) { - SOKOL_ASSERT(img && desc); - _SOKOL_UNUSED(img); - _SOKOL_UNUSED(desc); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_dummy_discard_image(_sg_image_t* img) { - SOKOL_ASSERT(img); - _SOKOL_UNUSED(img); -} - -_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_sampler(_sg_sampler_t* smp, const sg_sampler_desc* desc) { - SOKOL_ASSERT(smp && desc); - _SOKOL_UNUSED(smp); - _SOKOL_UNUSED(desc); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_dummy_discard_sampler(_sg_sampler_t* smp) { - SOKOL_ASSERT(smp); - _SOKOL_UNUSED(smp); -} - -_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { - SOKOL_ASSERT(shd && desc); - _SOKOL_UNUSED(shd); - _SOKOL_UNUSED(desc); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_dummy_discard_shader(_sg_shader_t* shd) { - SOKOL_ASSERT(shd); - _SOKOL_UNUSED(shd); -} - -_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { - SOKOL_ASSERT(pip && desc); - pip->shader = shd; - for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { - const sg_vertex_attr_state* a_state = &desc->layout.attrs[attr_index]; - if (a_state->format == SG_VERTEXFORMAT_INVALID) { - break; - } - SOKOL_ASSERT(a_state->buffer_index < SG_MAX_VERTEX_BUFFERS); - pip->cmn.vertex_buffer_layout_active[a_state->buffer_index] = true; - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_dummy_discard_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - _SOKOL_UNUSED(pip); -} - -_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_attachments_desc* desc) { - SOKOL_ASSERT(atts && desc); - SOKOL_ASSERT(color_images && resolve_images); - - for (int i = 0; i < atts->cmn.num_colors; i++) { - const sg_attachment_desc* color_desc = &desc->colors[i]; - _SOKOL_UNUSED(color_desc); - SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == atts->dmy.colors[i].image); - SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); - atts->dmy.colors[i].image = color_images[i]; - - const sg_attachment_desc* resolve_desc = &desc->resolves[i]; - if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == atts->dmy.resolves[i].image); - SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); - SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); - atts->dmy.resolves[i].image = resolve_images[i]; - } - } - - SOKOL_ASSERT(0 == atts->dmy.depth_stencil.image); - const sg_attachment_desc* ds_desc = &desc->depth_stencil; - if (ds_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(ds_img && (ds_img->slot.id == ds_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_img->cmn.pixel_format)); - atts->dmy.depth_stencil.image = ds_img; - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_dummy_discard_attachments(_sg_attachments_t* atts) { - SOKOL_ASSERT(atts); - _SOKOL_UNUSED(atts); -} - -_SOKOL_PRIVATE _sg_image_t* _sg_dummy_attachments_color_image(const _sg_attachments_t* atts, int index) { - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return atts->dmy.colors[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_dummy_attachments_resolve_image(const _sg_attachments_t* atts, int index) { - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return atts->dmy.resolves[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_dummy_attachments_ds_image(const _sg_attachments_t* atts) { - SOKOL_ASSERT(atts); - return atts->dmy.depth_stencil.image; -} - -_SOKOL_PRIVATE void _sg_dummy_begin_pass(const sg_pass* pass) { - SOKOL_ASSERT(pass); - _SOKOL_UNUSED(pass); -} - -_SOKOL_PRIVATE void _sg_dummy_end_pass(void) { - // empty -} - -_SOKOL_PRIVATE void _sg_dummy_commit(void) { - // empty -} - -_SOKOL_PRIVATE void _sg_dummy_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { - _SOKOL_UNUSED(x); - _SOKOL_UNUSED(y); - _SOKOL_UNUSED(w); - _SOKOL_UNUSED(h); - _SOKOL_UNUSED(origin_top_left); -} - -_SOKOL_PRIVATE void _sg_dummy_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - _SOKOL_UNUSED(x); - _SOKOL_UNUSED(y); - _SOKOL_UNUSED(w); - _SOKOL_UNUSED(h); - _SOKOL_UNUSED(origin_top_left); -} - -_SOKOL_PRIVATE void _sg_dummy_apply_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - _SOKOL_UNUSED(pip); -} - -_SOKOL_PRIVATE bool _sg_dummy_apply_bindings(_sg_bindings_t* bnd) { - SOKOL_ASSERT(bnd); - SOKOL_ASSERT(bnd->pip); - _SOKOL_UNUSED(bnd); - return true; -} - -_SOKOL_PRIVATE void _sg_dummy_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { - _SOKOL_UNUSED(stage_index); - _SOKOL_UNUSED(ub_index); - _SOKOL_UNUSED(data); -} - -_SOKOL_PRIVATE void _sg_dummy_draw(int base_element, int num_elements, int num_instances) { - _SOKOL_UNUSED(base_element); - _SOKOL_UNUSED(num_elements); - _SOKOL_UNUSED(num_instances); -} - -_SOKOL_PRIVATE void _sg_dummy_update_buffer(_sg_buffer_t* buf, const sg_range* data) { - SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); - _SOKOL_UNUSED(data); - if (++buf->cmn.active_slot >= buf->cmn.num_slots) { - buf->cmn.active_slot = 0; - } -} - -_SOKOL_PRIVATE bool _sg_dummy_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { - SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); - _SOKOL_UNUSED(data); - if (new_frame) { - if (++buf->cmn.active_slot >= buf->cmn.num_slots) { - buf->cmn.active_slot = 0; - } - } - return true; -} - -_SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_data* data) { - SOKOL_ASSERT(img && data); - _SOKOL_UNUSED(data); - if (++img->cmn.active_slot >= img->cmn.num_slots) { - img->cmn.active_slot = 0; - } -} - -// ██████ ██████ ███████ ███ ██ ██████ ██ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ -// ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██ ██ ██████ █████ ██ ██ ██ ██ ███ ██ ██████ ███████ ██ █████ █████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ███████ ██ ████ ██████ ███████ ██████ ██ ██ ██████ ██ ██ ███████ ██ ████ ██████ -// -// >>opengl backend -#elif defined(_SOKOL_ANY_GL) - -// optional GL loader for win32 -#if defined(_SOKOL_USE_WIN32_GL_LOADER) - -#ifndef SG_GL_FUNCS_EXT -#define SG_GL_FUNCS_EXT -#endif - -// X Macro list of GL function names and signatures -#define _SG_GL_FUNCS \ - SG_GL_FUNCS_EXT \ - _SG_XMACRO(glBindVertexArray, void, (GLuint array)) \ - _SG_XMACRO(glFramebufferTextureLayer, void, (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)) \ - _SG_XMACRO(glGenFramebuffers, void, (GLsizei n, GLuint * framebuffers)) \ - _SG_XMACRO(glBindFramebuffer, void, (GLenum target, GLuint framebuffer)) \ - _SG_XMACRO(glBindRenderbuffer, void, (GLenum target, GLuint renderbuffer)) \ - _SG_XMACRO(glGetStringi, const GLubyte *, (GLenum name, GLuint index)) \ - _SG_XMACRO(glClearBufferfi, void, (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)) \ - _SG_XMACRO(glClearBufferfv, void, (GLenum buffer, GLint drawbuffer, const GLfloat * value)) \ - _SG_XMACRO(glClearBufferuiv, void, (GLenum buffer, GLint drawbuffer, const GLuint * value)) \ - _SG_XMACRO(glClearBufferiv, void, (GLenum buffer, GLint drawbuffer, const GLint * value)) \ - _SG_XMACRO(glDeleteRenderbuffers, void, (GLsizei n, const GLuint * renderbuffers)) \ - _SG_XMACRO(glUniform1fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ - _SG_XMACRO(glUniform2fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ - _SG_XMACRO(glUniform3fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ - _SG_XMACRO(glUniform4fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ - _SG_XMACRO(glUniform1iv, void, (GLint location, GLsizei count, const GLint * value)) \ - _SG_XMACRO(glUniform2iv, void, (GLint location, GLsizei count, const GLint * value)) \ - _SG_XMACRO(glUniform3iv, void, (GLint location, GLsizei count, const GLint * value)) \ - _SG_XMACRO(glUniform4iv, void, (GLint location, GLsizei count, const GLint * value)) \ - _SG_XMACRO(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)) \ - _SG_XMACRO(glUseProgram, void, (GLuint program)) \ - _SG_XMACRO(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length)) \ - _SG_XMACRO(glLinkProgram, void, (GLuint program)) \ - _SG_XMACRO(glGetUniformLocation, GLint, (GLuint program, const GLchar * name)) \ - _SG_XMACRO(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint * params)) \ - _SG_XMACRO(glGetProgramInfoLog, void, (GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \ - _SG_XMACRO(glGetAttribLocation, GLint, (GLuint program, const GLchar * name)) \ - _SG_XMACRO(glDisableVertexAttribArray, void, (GLuint index)) \ - _SG_XMACRO(glDeleteShader, void, (GLuint shader)) \ - _SG_XMACRO(glDeleteProgram, void, (GLuint program)) \ - _SG_XMACRO(glCompileShader, void, (GLuint shader)) \ - _SG_XMACRO(glStencilFuncSeparate, void, (GLenum face, GLenum func, GLint ref, GLuint mask)) \ - _SG_XMACRO(glStencilOpSeparate, void, (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)) \ - _SG_XMACRO(glRenderbufferStorageMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)) \ - _SG_XMACRO(glDrawBuffers, void, (GLsizei n, const GLenum * bufs)) \ - _SG_XMACRO(glVertexAttribDivisor, void, (GLuint index, GLuint divisor)) \ - _SG_XMACRO(glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void * data)) \ - _SG_XMACRO(glGenBuffers, void, (GLsizei n, GLuint * buffers)) \ - _SG_XMACRO(glCheckFramebufferStatus, GLenum, (GLenum target)) \ - _SG_XMACRO(glFramebufferRenderbuffer, void, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) \ - _SG_XMACRO(glCompressedTexImage2D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data)) \ - _SG_XMACRO(glCompressedTexImage3D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data)) \ - _SG_XMACRO(glActiveTexture, void, (GLenum texture)) \ - _SG_XMACRO(glTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels)) \ - _SG_XMACRO(glRenderbufferStorage, void, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) \ - _SG_XMACRO(glGenTextures, void, (GLsizei n, GLuint * textures)) \ - _SG_XMACRO(glPolygonOffset, void, (GLfloat factor, GLfloat units)) \ - _SG_XMACRO(glDrawElements, void, (GLenum mode, GLsizei count, GLenum type, const void * indices)) \ - _SG_XMACRO(glDeleteFramebuffers, void, (GLsizei n, const GLuint * framebuffers)) \ - _SG_XMACRO(glBlendEquationSeparate, void, (GLenum modeRGB, GLenum modeAlpha)) \ - _SG_XMACRO(glDeleteTextures, void, (GLsizei n, const GLuint * textures)) \ - _SG_XMACRO(glGetProgramiv, void, (GLuint program, GLenum pname, GLint * params)) \ - _SG_XMACRO(glBindTexture, void, (GLenum target, GLuint texture)) \ - _SG_XMACRO(glTexImage3D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels)) \ - _SG_XMACRO(glCreateShader, GLuint, (GLenum type)) \ - _SG_XMACRO(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels)) \ - _SG_XMACRO(glFramebufferTexture2D, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) \ - _SG_XMACRO(glCreateProgram, GLuint, (void)) \ - _SG_XMACRO(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \ - _SG_XMACRO(glDeleteBuffers, void, (GLsizei n, const GLuint * buffers)) \ - _SG_XMACRO(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) \ - _SG_XMACRO(glDrawElementsInstanced, void, (GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount)) \ - _SG_XMACRO(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer)) \ - _SG_XMACRO(glUniform1i, void, (GLint location, GLint v0)) \ - _SG_XMACRO(glDisable, void, (GLenum cap)) \ - _SG_XMACRO(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \ - _SG_XMACRO(glColorMaski, void, (GLuint buf, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \ - _SG_XMACRO(glBindBuffer, void, (GLenum target, GLuint buffer)) \ - _SG_XMACRO(glDeleteVertexArrays, void, (GLsizei n, const GLuint * arrays)) \ - _SG_XMACRO(glDepthMask, void, (GLboolean flag)) \ - _SG_XMACRO(glDrawArraysInstanced, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount)) \ - _SG_XMACRO(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \ - _SG_XMACRO(glGenRenderbuffers, void, (GLsizei n, GLuint * renderbuffers)) \ - _SG_XMACRO(glBufferData, void, (GLenum target, GLsizeiptr size, const void * data, GLenum usage)) \ - _SG_XMACRO(glBlendFuncSeparate, void, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)) \ - _SG_XMACRO(glTexParameteri, void, (GLenum target, GLenum pname, GLint param)) \ - _SG_XMACRO(glGetIntegerv, void, (GLenum pname, GLint * data)) \ - _SG_XMACRO(glEnable, void, (GLenum cap)) \ - _SG_XMACRO(glBlitFramebuffer, void, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)) \ - _SG_XMACRO(glStencilMask, void, (GLuint mask)) \ - _SG_XMACRO(glAttachShader, void, (GLuint program, GLuint shader)) \ - _SG_XMACRO(glGetError, GLenum, (void)) \ - _SG_XMACRO(glBlendColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \ - _SG_XMACRO(glTexParameterf, void, (GLenum target, GLenum pname, GLfloat param)) \ - _SG_XMACRO(glTexParameterfv, void, (GLenum target, GLenum pname, const GLfloat* params)) \ - _SG_XMACRO(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \ - _SG_XMACRO(glDepthFunc, void, (GLenum func)) \ - _SG_XMACRO(glStencilOp , void, (GLenum fail, GLenum zfail, GLenum zpass)) \ - _SG_XMACRO(glStencilFunc, void, (GLenum func, GLint ref, GLuint mask)) \ - _SG_XMACRO(glEnableVertexAttribArray, void, (GLuint index)) \ - _SG_XMACRO(glBlendFunc, void, (GLenum sfactor, GLenum dfactor)) \ - _SG_XMACRO(glReadBuffer, void, (GLenum src)) \ - _SG_XMACRO(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels)) \ - _SG_XMACRO(glGenVertexArrays, void, (GLsizei n, GLuint * arrays)) \ - _SG_XMACRO(glFrontFace, void, (GLenum mode)) \ - _SG_XMACRO(glCullFace, void, (GLenum mode)) \ - _SG_XMACRO(glPixelStorei, void, (GLenum pname, GLint param)) \ - _SG_XMACRO(glBindSampler, void, (GLuint unit, GLuint sampler)) \ - _SG_XMACRO(glGenSamplers, void, (GLsizei n, GLuint* samplers)) \ - _SG_XMACRO(glSamplerParameteri, void, (GLuint sampler, GLenum pname, GLint param)) \ - _SG_XMACRO(glSamplerParameterf, void, (GLuint sampler, GLenum pname, GLfloat param)) \ - _SG_XMACRO(glSamplerParameterfv, void, (GLuint sampler, GLenum pname, const GLfloat* params)) \ - _SG_XMACRO(glDeleteSamplers, void, (GLsizei n, const GLuint* samplers)) \ - _SG_XMACRO(glBindBufferBase, void, (GLenum target, GLuint index, GLuint buffer)) - -// generate GL function pointer typedefs -#define _SG_XMACRO(name, ret, args) typedef ret (GL_APIENTRY* PFN_ ## name) args; -_SG_GL_FUNCS -#undef _SG_XMACRO - -// generate GL function pointers -#define _SG_XMACRO(name, ret, args) static PFN_ ## name name; -_SG_GL_FUNCS -#undef _SG_XMACRO - -// helper function to lookup GL functions in GL DLL -typedef PROC (WINAPI * _sg_wglGetProcAddress)(LPCSTR); -_SOKOL_PRIVATE void* _sg_gl_getprocaddr(const char* name, _sg_wglGetProcAddress wgl_getprocaddress) { - void* proc_addr = (void*) wgl_getprocaddress(name); - if (0 == proc_addr) { - proc_addr = (void*) GetProcAddress(_sg.gl.opengl32_dll, name); - } - SOKOL_ASSERT(proc_addr); - return proc_addr; -} - -// populate GL function pointers -_SOKOL_PRIVATE void _sg_gl_load_opengl(void) { - SOKOL_ASSERT(0 == _sg.gl.opengl32_dll); - _sg.gl.opengl32_dll = LoadLibraryA("opengl32.dll"); - SOKOL_ASSERT(_sg.gl.opengl32_dll); - _sg_wglGetProcAddress wgl_getprocaddress = (_sg_wglGetProcAddress) GetProcAddress(_sg.gl.opengl32_dll, "wglGetProcAddress"); - SOKOL_ASSERT(wgl_getprocaddress); - #define _SG_XMACRO(name, ret, args) name = (PFN_ ## name) _sg_gl_getprocaddr(#name, wgl_getprocaddress); - _SG_GL_FUNCS - #undef _SG_XMACRO -} - -_SOKOL_PRIVATE void _sg_gl_unload_opengl(void) { - SOKOL_ASSERT(_sg.gl.opengl32_dll); - FreeLibrary(_sg.gl.opengl32_dll); - _sg.gl.opengl32_dll = 0; -} -#endif // _SOKOL_USE_WIN32_GL_LOADER - -//-- type translation ---------------------------------------------------------- -_SOKOL_PRIVATE GLenum _sg_gl_buffer_target(sg_buffer_type t) { - switch (t) { - case SG_BUFFERTYPE_VERTEXBUFFER: return GL_ARRAY_BUFFER; - case SG_BUFFERTYPE_INDEXBUFFER: return GL_ELEMENT_ARRAY_BUFFER; - case SG_BUFFERTYPE_STORAGEBUFFER: return GL_SHADER_STORAGE_BUFFER; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_texture_target(sg_image_type t) { - switch (t) { - case SG_IMAGETYPE_2D: return GL_TEXTURE_2D; - case SG_IMAGETYPE_CUBE: return GL_TEXTURE_CUBE_MAP; - case SG_IMAGETYPE_3D: return GL_TEXTURE_3D; - case SG_IMAGETYPE_ARRAY: return GL_TEXTURE_2D_ARRAY; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_usage(sg_usage u) { - switch (u) { - case SG_USAGE_IMMUTABLE: return GL_STATIC_DRAW; - case SG_USAGE_DYNAMIC: return GL_DYNAMIC_DRAW; - case SG_USAGE_STREAM: return GL_STREAM_DRAW; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_shader_stage(sg_shader_stage stage) { - switch (stage) { - case SG_SHADERSTAGE_VS: return GL_VERTEX_SHADER; - case SG_SHADERSTAGE_FS: return GL_FRAGMENT_SHADER; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLint _sg_gl_vertexformat_size(sg_vertex_format fmt) { - switch (fmt) { - case SG_VERTEXFORMAT_FLOAT: return 1; - case SG_VERTEXFORMAT_FLOAT2: return 2; - case SG_VERTEXFORMAT_FLOAT3: return 3; - case SG_VERTEXFORMAT_FLOAT4: return 4; - case SG_VERTEXFORMAT_BYTE4: return 4; - case SG_VERTEXFORMAT_BYTE4N: return 4; - case SG_VERTEXFORMAT_UBYTE4: return 4; - case SG_VERTEXFORMAT_UBYTE4N: return 4; - case SG_VERTEXFORMAT_SHORT2: return 2; - case SG_VERTEXFORMAT_SHORT2N: return 2; - case SG_VERTEXFORMAT_USHORT2N: return 2; - case SG_VERTEXFORMAT_SHORT4: return 4; - case SG_VERTEXFORMAT_SHORT4N: return 4; - case SG_VERTEXFORMAT_USHORT4N: return 4; - case SG_VERTEXFORMAT_UINT10_N2: return 4; - case SG_VERTEXFORMAT_HALF2: return 2; - case SG_VERTEXFORMAT_HALF4: return 4; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_vertexformat_type(sg_vertex_format fmt) { - switch (fmt) { - case SG_VERTEXFORMAT_FLOAT: - case SG_VERTEXFORMAT_FLOAT2: - case SG_VERTEXFORMAT_FLOAT3: - case SG_VERTEXFORMAT_FLOAT4: - return GL_FLOAT; - case SG_VERTEXFORMAT_BYTE4: - case SG_VERTEXFORMAT_BYTE4N: - return GL_BYTE; - case SG_VERTEXFORMAT_UBYTE4: - case SG_VERTEXFORMAT_UBYTE4N: - return GL_UNSIGNED_BYTE; - case SG_VERTEXFORMAT_SHORT2: - case SG_VERTEXFORMAT_SHORT2N: - case SG_VERTEXFORMAT_SHORT4: - case SG_VERTEXFORMAT_SHORT4N: - return GL_SHORT; - case SG_VERTEXFORMAT_USHORT2N: - case SG_VERTEXFORMAT_USHORT4N: - return GL_UNSIGNED_SHORT; - case SG_VERTEXFORMAT_UINT10_N2: - return GL_UNSIGNED_INT_2_10_10_10_REV; - case SG_VERTEXFORMAT_HALF2: - case SG_VERTEXFORMAT_HALF4: - return GL_HALF_FLOAT; - default: - SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLboolean _sg_gl_vertexformat_normalized(sg_vertex_format fmt) { - switch (fmt) { - case SG_VERTEXFORMAT_BYTE4N: - case SG_VERTEXFORMAT_UBYTE4N: - case SG_VERTEXFORMAT_SHORT2N: - case SG_VERTEXFORMAT_USHORT2N: - case SG_VERTEXFORMAT_SHORT4N: - case SG_VERTEXFORMAT_USHORT4N: - case SG_VERTEXFORMAT_UINT10_N2: - return GL_TRUE; - default: - return GL_FALSE; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_primitive_type(sg_primitive_type t) { - switch (t) { - case SG_PRIMITIVETYPE_POINTS: return GL_POINTS; - case SG_PRIMITIVETYPE_LINES: return GL_LINES; - case SG_PRIMITIVETYPE_LINE_STRIP: return GL_LINE_STRIP; - case SG_PRIMITIVETYPE_TRIANGLES: return GL_TRIANGLES; - case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_index_type(sg_index_type t) { - switch (t) { - case SG_INDEXTYPE_NONE: return 0; - case SG_INDEXTYPE_UINT16: return GL_UNSIGNED_SHORT; - case SG_INDEXTYPE_UINT32: return GL_UNSIGNED_INT; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_compare_func(sg_compare_func cmp) { - switch (cmp) { - case SG_COMPAREFUNC_NEVER: return GL_NEVER; - case SG_COMPAREFUNC_LESS: return GL_LESS; - case SG_COMPAREFUNC_EQUAL: return GL_EQUAL; - case SG_COMPAREFUNC_LESS_EQUAL: return GL_LEQUAL; - case SG_COMPAREFUNC_GREATER: return GL_GREATER; - case SG_COMPAREFUNC_NOT_EQUAL: return GL_NOTEQUAL; - case SG_COMPAREFUNC_GREATER_EQUAL: return GL_GEQUAL; - case SG_COMPAREFUNC_ALWAYS: return GL_ALWAYS; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_stencil_op(sg_stencil_op op) { - switch (op) { - case SG_STENCILOP_KEEP: return GL_KEEP; - case SG_STENCILOP_ZERO: return GL_ZERO; - case SG_STENCILOP_REPLACE: return GL_REPLACE; - case SG_STENCILOP_INCR_CLAMP: return GL_INCR; - case SG_STENCILOP_DECR_CLAMP: return GL_DECR; - case SG_STENCILOP_INVERT: return GL_INVERT; - case SG_STENCILOP_INCR_WRAP: return GL_INCR_WRAP; - case SG_STENCILOP_DECR_WRAP: return GL_DECR_WRAP; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_blend_factor(sg_blend_factor f) { - switch (f) { - case SG_BLENDFACTOR_ZERO: return GL_ZERO; - case SG_BLENDFACTOR_ONE: return GL_ONE; - case SG_BLENDFACTOR_SRC_COLOR: return GL_SRC_COLOR; - case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR; - case SG_BLENDFACTOR_SRC_ALPHA: return GL_SRC_ALPHA; - case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; - case SG_BLENDFACTOR_DST_COLOR: return GL_DST_COLOR; - case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR; - case SG_BLENDFACTOR_DST_ALPHA: return GL_DST_ALPHA; - case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; - case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return GL_SRC_ALPHA_SATURATE; - case SG_BLENDFACTOR_BLEND_COLOR: return GL_CONSTANT_COLOR; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR; - case SG_BLENDFACTOR_BLEND_ALPHA: return GL_CONSTANT_ALPHA; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_blend_op(sg_blend_op op) { - switch (op) { - case SG_BLENDOP_ADD: return GL_FUNC_ADD; - case SG_BLENDOP_SUBTRACT: return GL_FUNC_SUBTRACT; - case SG_BLENDOP_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_min_filter(sg_filter min_f, sg_filter mipmap_f) { - if (min_f == SG_FILTER_NEAREST) { - switch (mipmap_f) { - case SG_FILTER_NEAREST: return GL_NEAREST_MIPMAP_NEAREST; - case SG_FILTER_LINEAR: return GL_NEAREST_MIPMAP_LINEAR; - default: SOKOL_UNREACHABLE; return (GLenum)0; - } - } else if (min_f == SG_FILTER_LINEAR) { - switch (mipmap_f) { - case SG_FILTER_NEAREST: return GL_LINEAR_MIPMAP_NEAREST; - case SG_FILTER_LINEAR: return GL_LINEAR_MIPMAP_LINEAR; - default: SOKOL_UNREACHABLE; return (GLenum)0; - } - } else { - SOKOL_UNREACHABLE; return (GLenum)0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_mag_filter(sg_filter mag_f) { - if (mag_f == SG_FILTER_NEAREST) { - return GL_NEAREST; - } else { - return GL_LINEAR; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_wrap(sg_wrap w) { - switch (w) { - case SG_WRAP_CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE; - #if defined(SOKOL_GLCORE) - case SG_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER; - #else - case SG_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_EDGE; - #endif - case SG_WRAP_REPEAT: return GL_REPEAT; - case SG_WRAP_MIRRORED_REPEAT: return GL_MIRRORED_REPEAT; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_teximage_type(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_R8: - case SG_PIXELFORMAT_R8UI: - case SG_PIXELFORMAT_RG8: - case SG_PIXELFORMAT_RG8UI: - case SG_PIXELFORMAT_RGBA8: - case SG_PIXELFORMAT_SRGB8A8: - case SG_PIXELFORMAT_RGBA8UI: - case SG_PIXELFORMAT_BGRA8: - return GL_UNSIGNED_BYTE; - case SG_PIXELFORMAT_R8SN: - case SG_PIXELFORMAT_R8SI: - case SG_PIXELFORMAT_RG8SN: - case SG_PIXELFORMAT_RG8SI: - case SG_PIXELFORMAT_RGBA8SN: - case SG_PIXELFORMAT_RGBA8SI: - return GL_BYTE; - case SG_PIXELFORMAT_R16: - case SG_PIXELFORMAT_R16UI: - case SG_PIXELFORMAT_RG16: - case SG_PIXELFORMAT_RG16UI: - case SG_PIXELFORMAT_RGBA16: - case SG_PIXELFORMAT_RGBA16UI: - return GL_UNSIGNED_SHORT; - case SG_PIXELFORMAT_R16SN: - case SG_PIXELFORMAT_R16SI: - case SG_PIXELFORMAT_RG16SN: - case SG_PIXELFORMAT_RG16SI: - case SG_PIXELFORMAT_RGBA16SN: - case SG_PIXELFORMAT_RGBA16SI: - return GL_SHORT; - case SG_PIXELFORMAT_R16F: - case SG_PIXELFORMAT_RG16F: - case SG_PIXELFORMAT_RGBA16F: - return GL_HALF_FLOAT; - case SG_PIXELFORMAT_R32UI: - case SG_PIXELFORMAT_RG32UI: - case SG_PIXELFORMAT_RGBA32UI: - return GL_UNSIGNED_INT; - case SG_PIXELFORMAT_R32SI: - case SG_PIXELFORMAT_RG32SI: - case SG_PIXELFORMAT_RGBA32SI: - return GL_INT; - case SG_PIXELFORMAT_R32F: - case SG_PIXELFORMAT_RG32F: - case SG_PIXELFORMAT_RGBA32F: - return GL_FLOAT; - case SG_PIXELFORMAT_RGB10A2: - return GL_UNSIGNED_INT_2_10_10_10_REV; - case SG_PIXELFORMAT_RG11B10F: - return GL_UNSIGNED_INT_10F_11F_11F_REV; - case SG_PIXELFORMAT_RGB9E5: - return GL_UNSIGNED_INT_5_9_9_9_REV; - case SG_PIXELFORMAT_DEPTH: - return GL_FLOAT; - case SG_PIXELFORMAT_DEPTH_STENCIL: - return GL_UNSIGNED_INT_24_8; - default: - SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_teximage_format(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_R8: - case SG_PIXELFORMAT_R8SN: - case SG_PIXELFORMAT_R16: - case SG_PIXELFORMAT_R16SN: - case SG_PIXELFORMAT_R16F: - case SG_PIXELFORMAT_R32F: - return GL_RED; - case SG_PIXELFORMAT_R8UI: - case SG_PIXELFORMAT_R8SI: - case SG_PIXELFORMAT_R16UI: - case SG_PIXELFORMAT_R16SI: - case SG_PIXELFORMAT_R32UI: - case SG_PIXELFORMAT_R32SI: - return GL_RED_INTEGER; - case SG_PIXELFORMAT_RG8: - case SG_PIXELFORMAT_RG8SN: - case SG_PIXELFORMAT_RG16: - case SG_PIXELFORMAT_RG16SN: - case SG_PIXELFORMAT_RG16F: - case SG_PIXELFORMAT_RG32F: - return GL_RG; - case SG_PIXELFORMAT_RG8UI: - case SG_PIXELFORMAT_RG8SI: - case SG_PIXELFORMAT_RG16UI: - case SG_PIXELFORMAT_RG16SI: - case SG_PIXELFORMAT_RG32UI: - case SG_PIXELFORMAT_RG32SI: - return GL_RG_INTEGER; - case SG_PIXELFORMAT_RGBA8: - case SG_PIXELFORMAT_SRGB8A8: - case SG_PIXELFORMAT_RGBA8SN: - case SG_PIXELFORMAT_RGBA16: - case SG_PIXELFORMAT_RGBA16SN: - case SG_PIXELFORMAT_RGBA16F: - case SG_PIXELFORMAT_RGBA32F: - case SG_PIXELFORMAT_RGB10A2: - return GL_RGBA; - case SG_PIXELFORMAT_RGBA8UI: - case SG_PIXELFORMAT_RGBA8SI: - case SG_PIXELFORMAT_RGBA16UI: - case SG_PIXELFORMAT_RGBA16SI: - case SG_PIXELFORMAT_RGBA32UI: - case SG_PIXELFORMAT_RGBA32SI: - return GL_RGBA_INTEGER; - case SG_PIXELFORMAT_RG11B10F: - case SG_PIXELFORMAT_RGB9E5: - return GL_RGB; - case SG_PIXELFORMAT_DEPTH: - return GL_DEPTH_COMPONENT; - case SG_PIXELFORMAT_DEPTH_STENCIL: - return GL_DEPTH_STENCIL; - case SG_PIXELFORMAT_BC1_RGBA: - return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - case SG_PIXELFORMAT_BC2_RGBA: - return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - case SG_PIXELFORMAT_BC3_RGBA: - return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - case SG_PIXELFORMAT_BC3_SRGBA: - return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; - case SG_PIXELFORMAT_BC4_R: - return GL_COMPRESSED_RED_RGTC1; - case SG_PIXELFORMAT_BC4_RSN: - return GL_COMPRESSED_SIGNED_RED_RGTC1; - case SG_PIXELFORMAT_BC5_RG: - return GL_COMPRESSED_RED_GREEN_RGTC2; - case SG_PIXELFORMAT_BC5_RGSN: - return GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2; - case SG_PIXELFORMAT_BC6H_RGBF: - return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB; - case SG_PIXELFORMAT_BC6H_RGBUF: - return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB; - case SG_PIXELFORMAT_BC7_RGBA: - return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; - case SG_PIXELFORMAT_BC7_SRGBA: - return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB; - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: - return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: - return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: - return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: - return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - case SG_PIXELFORMAT_ETC2_RGB8: - return GL_COMPRESSED_RGB8_ETC2; - case SG_PIXELFORMAT_ETC2_SRGB8: - return GL_COMPRESSED_SRGB8_ETC2; - case SG_PIXELFORMAT_ETC2_RGB8A1: - return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; - case SG_PIXELFORMAT_ETC2_RGBA8: - return GL_COMPRESSED_RGBA8_ETC2_EAC; - case SG_PIXELFORMAT_ETC2_SRGB8A8: - return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; - case SG_PIXELFORMAT_EAC_R11: - return GL_COMPRESSED_R11_EAC; - case SG_PIXELFORMAT_EAC_R11SN: - return GL_COMPRESSED_SIGNED_R11_EAC; - case SG_PIXELFORMAT_EAC_RG11: - return GL_COMPRESSED_RG11_EAC; - case SG_PIXELFORMAT_EAC_RG11SN: - return GL_COMPRESSED_SIGNED_RG11_EAC; - case SG_PIXELFORMAT_ASTC_4x4_RGBA: - return GL_COMPRESSED_RGBA_ASTC_4x4_KHR; - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: - return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; - default: - SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_teximage_internal_format(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_R8: return GL_R8; - case SG_PIXELFORMAT_R8SN: return GL_R8_SNORM; - case SG_PIXELFORMAT_R8UI: return GL_R8UI; - case SG_PIXELFORMAT_R8SI: return GL_R8I; - #if !defined(SOKOL_GLES3) - case SG_PIXELFORMAT_R16: return GL_R16; - case SG_PIXELFORMAT_R16SN: return GL_R16_SNORM; - #endif - case SG_PIXELFORMAT_R16UI: return GL_R16UI; - case SG_PIXELFORMAT_R16SI: return GL_R16I; - case SG_PIXELFORMAT_R16F: return GL_R16F; - case SG_PIXELFORMAT_RG8: return GL_RG8; - case SG_PIXELFORMAT_RG8SN: return GL_RG8_SNORM; - case SG_PIXELFORMAT_RG8UI: return GL_RG8UI; - case SG_PIXELFORMAT_RG8SI: return GL_RG8I; - case SG_PIXELFORMAT_R32UI: return GL_R32UI; - case SG_PIXELFORMAT_R32SI: return GL_R32I; - case SG_PIXELFORMAT_R32F: return GL_R32F; - #if !defined(SOKOL_GLES3) - case SG_PIXELFORMAT_RG16: return GL_RG16; - case SG_PIXELFORMAT_RG16SN: return GL_RG16_SNORM; - #endif - case SG_PIXELFORMAT_RG16UI: return GL_RG16UI; - case SG_PIXELFORMAT_RG16SI: return GL_RG16I; - case SG_PIXELFORMAT_RG16F: return GL_RG16F; - case SG_PIXELFORMAT_RGBA8: return GL_RGBA8; - case SG_PIXELFORMAT_SRGB8A8: return GL_SRGB8_ALPHA8; - case SG_PIXELFORMAT_RGBA8SN: return GL_RGBA8_SNORM; - case SG_PIXELFORMAT_RGBA8UI: return GL_RGBA8UI; - case SG_PIXELFORMAT_RGBA8SI: return GL_RGBA8I; - case SG_PIXELFORMAT_RGB10A2: return GL_RGB10_A2; - case SG_PIXELFORMAT_RG11B10F: return GL_R11F_G11F_B10F; - case SG_PIXELFORMAT_RGB9E5: return GL_RGB9_E5; - case SG_PIXELFORMAT_RG32UI: return GL_RG32UI; - case SG_PIXELFORMAT_RG32SI: return GL_RG32I; - case SG_PIXELFORMAT_RG32F: return GL_RG32F; - #if !defined(SOKOL_GLES3) - case SG_PIXELFORMAT_RGBA16: return GL_RGBA16; - case SG_PIXELFORMAT_RGBA16SN: return GL_RGBA16_SNORM; - #endif - case SG_PIXELFORMAT_RGBA16UI: return GL_RGBA16UI; - case SG_PIXELFORMAT_RGBA16SI: return GL_RGBA16I; - case SG_PIXELFORMAT_RGBA16F: return GL_RGBA16F; - case SG_PIXELFORMAT_RGBA32UI: return GL_RGBA32UI; - case SG_PIXELFORMAT_RGBA32SI: return GL_RGBA32I; - case SG_PIXELFORMAT_RGBA32F: return GL_RGBA32F; - case SG_PIXELFORMAT_DEPTH: return GL_DEPTH_COMPONENT32F; - case SG_PIXELFORMAT_DEPTH_STENCIL: return GL_DEPTH24_STENCIL8; - case SG_PIXELFORMAT_BC1_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - case SG_PIXELFORMAT_BC2_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - case SG_PIXELFORMAT_BC3_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - case SG_PIXELFORMAT_BC3_SRGBA: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; - case SG_PIXELFORMAT_BC4_R: return GL_COMPRESSED_RED_RGTC1; - case SG_PIXELFORMAT_BC4_RSN: return GL_COMPRESSED_SIGNED_RED_RGTC1; - case SG_PIXELFORMAT_BC5_RG: return GL_COMPRESSED_RED_GREEN_RGTC2; - case SG_PIXELFORMAT_BC5_RGSN: return GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2; - case SG_PIXELFORMAT_BC6H_RGBF: return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB; - case SG_PIXELFORMAT_BC6H_RGBUF: return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB; - case SG_PIXELFORMAT_BC7_RGBA: return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; - case SG_PIXELFORMAT_BC7_SRGBA: return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB; - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - case SG_PIXELFORMAT_ETC2_RGB8: return GL_COMPRESSED_RGB8_ETC2; - case SG_PIXELFORMAT_ETC2_SRGB8: return GL_COMPRESSED_SRGB8_ETC2; - case SG_PIXELFORMAT_ETC2_RGB8A1: return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; - case SG_PIXELFORMAT_ETC2_RGBA8: return GL_COMPRESSED_RGBA8_ETC2_EAC; - case SG_PIXELFORMAT_ETC2_SRGB8A8: return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; - case SG_PIXELFORMAT_EAC_R11: return GL_COMPRESSED_R11_EAC; - case SG_PIXELFORMAT_EAC_R11SN: return GL_COMPRESSED_SIGNED_R11_EAC; - case SG_PIXELFORMAT_EAC_RG11: return GL_COMPRESSED_RG11_EAC; - case SG_PIXELFORMAT_EAC_RG11SN: return GL_COMPRESSED_SIGNED_RG11_EAC; - case SG_PIXELFORMAT_ASTC_4x4_RGBA: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR; - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_cubeface_target(int face_index) { - switch (face_index) { - case 0: return GL_TEXTURE_CUBE_MAP_POSITIVE_X; - case 1: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X; - case 2: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y; - case 3: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; - case 4: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z; - case 5: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; - default: SOKOL_UNREACHABLE; return 0; - } -} - -// see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml -_SOKOL_PRIVATE void _sg_gl_init_pixelformats(bool has_bgra) { - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8SN]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8SI]); - #if !defined(SOKOL_GLES3) - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16SN]); - #endif - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16SI]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG8SN]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32SI]); - #if !defined(SOKOL_GLES3) - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16SN]); - #endif - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16SI]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_SRGB8A8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA8SN]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8SI]); - if (has_bgra) { - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_BGRA8]); - } - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGB10A2]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG11B10F]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGB9E5]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32SI]); - #if !defined(SOKOL_GLES3) - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16SN]); - #endif - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16SI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); - _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH]); - _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL]); -} - -// FIXME: OES_half_float_blend -_SOKOL_PRIVATE void _sg_gl_init_pixelformats_half_float(bool has_colorbuffer_half_float) { - if (has_colorbuffer_half_float) { - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16F]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16F]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); - } else { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R16F]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG16F]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); - } -} - -_SOKOL_PRIVATE void _sg_gl_init_pixelformats_float(bool has_colorbuffer_float, bool has_texture_float_linear, bool has_float_blend) { - if (has_texture_float_linear) { - if (has_colorbuffer_float) { - if (has_float_blend) { - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R32F]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG32F]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); - } else { - _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_R32F]); - _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_RG32F]); - _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); - } - } else { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R32F]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG32F]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); - } - } else { - if (has_colorbuffer_float) { - _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_R32F]); - _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RG32F]); - _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); - } else { - _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_R32F]); - _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RG32F]); - _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); - } - } -} - -_SOKOL_PRIVATE void _sg_gl_init_pixelformats_s3tc(void) { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC1_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC2_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_SRGBA]); -} - -_SOKOL_PRIVATE void _sg_gl_init_pixelformats_rgtc(void) { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_R]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_RSN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RG]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RGSN]); -} - -_SOKOL_PRIVATE void _sg_gl_init_pixelformats_bptc(void) { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBF]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBUF]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_SRGBA]); -} - -_SOKOL_PRIVATE void _sg_gl_init_pixelformats_pvrtc(void) { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_2BPP]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_4BPP]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_2BPP]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_4BPP]); -} - -_SOKOL_PRIVATE void _sg_gl_init_pixelformats_etc2(void) { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8A8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11SN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11SN]); -} - -_SOKOL_PRIVATE void _sg_gl_init_pixelformats_astc(void) { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_SRGBA]); - } - -_SOKOL_PRIVATE void _sg_gl_init_limits(void) { - _SG_GL_CHECK_ERROR(); - GLint gl_int; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_int); - _SG_GL_CHECK_ERROR(); - _sg.limits.max_image_size_2d = gl_int; - _sg.limits.max_image_size_array = gl_int; - glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &gl_int); - _SG_GL_CHECK_ERROR(); - _sg.limits.max_image_size_cube = gl_int; - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &gl_int); - _SG_GL_CHECK_ERROR(); - if (gl_int > SG_MAX_VERTEX_ATTRIBUTES) { - gl_int = SG_MAX_VERTEX_ATTRIBUTES; - } - _sg.limits.max_vertex_attrs = gl_int; - glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &gl_int); - _SG_GL_CHECK_ERROR(); - _sg.limits.gl_max_vertex_uniform_components = gl_int; - glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gl_int); - _SG_GL_CHECK_ERROR(); - _sg.limits.max_image_size_3d = gl_int; - glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &gl_int); - _SG_GL_CHECK_ERROR(); - _sg.limits.max_image_array_layers = gl_int; - if (_sg.gl.ext_anisotropic) { - glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_int); - _SG_GL_CHECK_ERROR(); - _sg.gl.max_anisotropy = gl_int; - } else { - _sg.gl.max_anisotropy = 1; - } - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gl_int); - _SG_GL_CHECK_ERROR(); - _sg.limits.gl_max_combined_texture_image_units = gl_int; -} - -#if defined(SOKOL_GLCORE) -_SOKOL_PRIVATE void _sg_gl_init_caps_glcore(void) { - _sg.backend = SG_BACKEND_GLCORE; - - GLint major_version = 0; - GLint minor_version = 0; - glGetIntegerv(GL_MAJOR_VERSION, &major_version); - glGetIntegerv(GL_MINOR_VERSION, &minor_version); - const int version = major_version * 100 + minor_version * 10; - _sg.features.origin_top_left = false; - _sg.features.image_clamp_to_border = true; - _sg.features.mrt_independent_blend_state = false; - _sg.features.mrt_independent_write_mask = true; - _sg.features.storage_buffer = version >= 430; - - // scan extensions - bool has_s3tc = false; // BC1..BC3 - bool has_rgtc = false; // BC4 and BC5 - bool has_bptc = false; // BC6H and BC7 - bool has_pvrtc = false; - bool has_etc2 = false; - bool has_astc = false; - GLint num_ext = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &num_ext); - for (int i = 0; i < num_ext; i++) { - const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, (GLuint)i); - if (ext) { - if (strstr(ext, "_texture_compression_s3tc")) { - has_s3tc = true; - } else if (strstr(ext, "_texture_compression_rgtc")) { - has_rgtc = true; - } else if (strstr(ext, "_texture_compression_bptc")) { - has_bptc = true; - } else if (strstr(ext, "_texture_compression_pvrtc")) { - has_pvrtc = true; - } else if (strstr(ext, "_ES3_compatibility")) { - has_etc2 = true; - } else if (strstr(ext, "_texture_filter_anisotropic")) { - _sg.gl.ext_anisotropic = true; - } else if (strstr(ext, "_texture_compression_astc_ldr")) { - has_astc = true; - } - } - } - - // limits - _sg_gl_init_limits(); - - // pixel formats - const bool has_bgra = false; // not a bug - const bool has_colorbuffer_float = true; - const bool has_colorbuffer_half_float = true; - const bool has_texture_float_linear = true; // FIXME??? - const bool has_float_blend = true; - _sg_gl_init_pixelformats(has_bgra); - _sg_gl_init_pixelformats_float(has_colorbuffer_float, has_texture_float_linear, has_float_blend); - _sg_gl_init_pixelformats_half_float(has_colorbuffer_half_float); - if (has_s3tc) { - _sg_gl_init_pixelformats_s3tc(); - } - if (has_rgtc) { - _sg_gl_init_pixelformats_rgtc(); - } - if (has_bptc) { - _sg_gl_init_pixelformats_bptc(); - } - if (has_pvrtc) { - _sg_gl_init_pixelformats_pvrtc(); - } - if (has_etc2) { - _sg_gl_init_pixelformats_etc2(); - } - if (has_astc) { - _sg_gl_init_pixelformats_astc(); - } -} -#endif - -#if defined(SOKOL_GLES3) -_SOKOL_PRIVATE void _sg_gl_init_caps_gles3(void) { - _sg.backend = SG_BACKEND_GLES3; - - _sg.features.origin_top_left = false; - _sg.features.image_clamp_to_border = false; - _sg.features.mrt_independent_blend_state = false; - _sg.features.mrt_independent_write_mask = false; - _sg.features.storage_buffer = false; - - bool has_s3tc = false; // BC1..BC3 - bool has_rgtc = false; // BC4 and BC5 - bool has_bptc = false; // BC6H and BC7 - bool has_pvrtc = false; - #if defined(__EMSCRIPTEN__) - bool has_etc2 = false; - #else - bool has_etc2 = true; - #endif - bool has_astc = false; - bool has_colorbuffer_float = false; - bool has_colorbuffer_half_float = false; - bool has_texture_float_linear = false; - bool has_float_blend = false; - GLint num_ext = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &num_ext); - for (int i = 0; i < num_ext; i++) { - const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, (GLuint)i); - if (ext) { - if (strstr(ext, "_texture_compression_s3tc")) { - has_s3tc = true; - } else if (strstr(ext, "_compressed_texture_s3tc")) { - has_s3tc = true; - } else if (strstr(ext, "_texture_compression_rgtc")) { - has_rgtc = true; - } else if (strstr(ext, "_texture_compression_bptc")) { - has_bptc = true; - } else if (strstr(ext, "_texture_compression_pvrtc")) { - has_pvrtc = true; - } else if (strstr(ext, "_compressed_texture_pvrtc")) { - has_pvrtc = true; - } else if (strstr(ext, "_compressed_texture_etc")) { - has_etc2 = true; - } else if (strstr(ext, "_compressed_texture_astc")) { - has_astc = true; - } else if (strstr(ext, "_color_buffer_float")) { - has_colorbuffer_float = true; - } else if (strstr(ext, "_color_buffer_half_float")) { - has_colorbuffer_half_float = true; - } else if (strstr(ext, "_texture_float_linear")) { - has_texture_float_linear = true; - } else if (strstr(ext, "_float_blend")) { - has_float_blend = true; - } else if (strstr(ext, "_texture_filter_anisotropic")) { - _sg.gl.ext_anisotropic = true; - } - } - } - - /* on WebGL2, color_buffer_float also includes 16-bit formats - see: https://developer.mozilla.org/en-US/docs/Web/API/EXT_color_buffer_float - */ - #if defined(__EMSCRIPTEN__) - if (!has_colorbuffer_half_float && has_colorbuffer_float) { - has_colorbuffer_half_float = has_colorbuffer_float; - } - #endif - - // limits - _sg_gl_init_limits(); - - // pixel formats - const bool has_bgra = false; // not a bug - _sg_gl_init_pixelformats(has_bgra); - _sg_gl_init_pixelformats_float(has_colorbuffer_float, has_texture_float_linear, has_float_blend); - _sg_gl_init_pixelformats_half_float(has_colorbuffer_half_float); - if (has_s3tc) { - _sg_gl_init_pixelformats_s3tc(); - } - if (has_rgtc) { - _sg_gl_init_pixelformats_rgtc(); - } - if (has_bptc) { - _sg_gl_init_pixelformats_bptc(); - } - if (has_pvrtc) { - _sg_gl_init_pixelformats_pvrtc(); - } - if (has_etc2) { - _sg_gl_init_pixelformats_etc2(); - } - if (has_astc) { - _sg_gl_init_pixelformats_astc(); - } -} -#endif - -//-- state cache implementation ------------------------------------------------ -_SOKOL_PRIVATE GLuint _sg_gl_storagebuffer_bind_index(int stage, int slot) { - SOKOL_ASSERT((stage >= 0) && (stage < SG_NUM_SHADER_STAGES)); - SOKOL_ASSERT((slot >= 0) && (slot < SG_MAX_SHADERSTAGE_STORAGEBUFFERS)); - return (GLuint) (stage * _SG_GL_STORAGEBUFFER_STAGE_INDEX_PITCH + slot); -} - -_SOKOL_PRIVATE void _sg_gl_cache_clear_buffer_bindings(bool force) { - if (force || (_sg.gl.cache.vertex_buffer != 0)) { - glBindBuffer(GL_ARRAY_BUFFER, 0); - _sg.gl.cache.vertex_buffer = 0; - _sg_stats_add(gl.num_bind_buffer, 1); - } - if (force || (_sg.gl.cache.index_buffer != 0)) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - _sg.gl.cache.index_buffer = 0; - _sg_stats_add(gl.num_bind_buffer, 1); - } - if (force || (_sg.gl.cache.storage_buffer != 0)) { - if (_sg.features.storage_buffer) { - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); - } - _sg.gl.cache.storage_buffer = 0; - _sg_stats_add(gl.num_bind_buffer, 1); - } - for (int stage = 0; stage < SG_NUM_SHADER_STAGES; stage++) { - for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { - if (force || (_sg.gl.cache.stage_storage_buffers[stage][i] != 0)) { - const GLuint bind_index = _sg_gl_storagebuffer_bind_index(stage, i); - if (_sg.features.storage_buffer) { - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, bind_index, 0); - } - _sg.gl.cache.stage_storage_buffers[stage][i] = 0; - _sg_stats_add(gl.num_bind_buffer, 1); - } - } - } -} - -_SOKOL_PRIVATE void _sg_gl_cache_bind_buffer(GLenum target, GLuint buffer) { - SOKOL_ASSERT((GL_ARRAY_BUFFER == target) || (GL_ELEMENT_ARRAY_BUFFER == target) || (GL_SHADER_STORAGE_BUFFER == target)); - if (target == GL_ARRAY_BUFFER) { - if (_sg.gl.cache.vertex_buffer != buffer) { - _sg.gl.cache.vertex_buffer = buffer; - glBindBuffer(target, buffer); - _sg_stats_add(gl.num_bind_buffer, 1); - } - } else if (target == GL_ELEMENT_ARRAY_BUFFER) { - if (_sg.gl.cache.index_buffer != buffer) { - _sg.gl.cache.index_buffer = buffer; - glBindBuffer(target, buffer); - _sg_stats_add(gl.num_bind_buffer, 1); - } - } else if (target == GL_SHADER_STORAGE_BUFFER) { - if (_sg.gl.cache.storage_buffer != buffer) { - _sg.gl.cache.storage_buffer = buffer; - if (_sg.features.storage_buffer) { - glBindBuffer(target, buffer); - } - _sg_stats_add(gl.num_bind_buffer, 1); - } - } else { - SOKOL_UNREACHABLE; - } -} - -_SOKOL_PRIVATE void _sg_gl_cache_bind_storage_buffer(int stage, int slot, GLuint buffer) { - SOKOL_ASSERT((stage >= 0) && (stage < SG_NUM_SHADER_STAGES)); - SOKOL_ASSERT((slot >= 0) && (slot < SG_MAX_SHADERSTAGE_STORAGEBUFFERS)); - if (_sg.gl.cache.stage_storage_buffers[stage][slot] != buffer) { - _sg.gl.cache.stage_storage_buffers[stage][slot] = buffer; - _sg.gl.cache.storage_buffer = buffer; // not a bug - GLuint bind_index = _sg_gl_storagebuffer_bind_index(stage, slot); - if (_sg.features.storage_buffer) { - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, bind_index, buffer); - } - _sg_stats_add(gl.num_bind_buffer, 1); - } -} - -_SOKOL_PRIVATE void _sg_gl_cache_store_buffer_binding(GLenum target) { - if (target == GL_ARRAY_BUFFER) { - _sg.gl.cache.stored_vertex_buffer = _sg.gl.cache.vertex_buffer; - } else if (target == GL_ELEMENT_ARRAY_BUFFER) { - _sg.gl.cache.stored_index_buffer = _sg.gl.cache.index_buffer; - } else if (target == GL_SHADER_STORAGE_BUFFER) { - _sg.gl.cache.stored_storage_buffer = _sg.gl.cache.storage_buffer; - } else { - SOKOL_UNREACHABLE; - } -} - -_SOKOL_PRIVATE void _sg_gl_cache_restore_buffer_binding(GLenum target) { - if (target == GL_ARRAY_BUFFER) { - if (_sg.gl.cache.stored_vertex_buffer != 0) { - // we only care about restoring valid ids - _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_vertex_buffer); - _sg.gl.cache.stored_vertex_buffer = 0; - } - } else if (target == GL_ELEMENT_ARRAY_BUFFER) { - if (_sg.gl.cache.stored_index_buffer != 0) { - // we only care about restoring valid ids - _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_index_buffer); - _sg.gl.cache.stored_index_buffer = 0; - } - } else if (target == GL_SHADER_STORAGE_BUFFER) { - if (_sg.gl.cache.stored_storage_buffer != 0) { - // we only care about restoring valid ids - _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_storage_buffer); - _sg.gl.cache.stored_storage_buffer = 0; - } - } else { - SOKOL_UNREACHABLE; - } -} - -// called when _sg_gl_discard_buffer() -_SOKOL_PRIVATE void _sg_gl_cache_invalidate_buffer(GLuint buf) { - if (buf == _sg.gl.cache.vertex_buffer) { - _sg.gl.cache.vertex_buffer = 0; - glBindBuffer(GL_ARRAY_BUFFER, 0); - _sg_stats_add(gl.num_bind_buffer, 1); - } - if (buf == _sg.gl.cache.index_buffer) { - _sg.gl.cache.index_buffer = 0; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - _sg_stats_add(gl.num_bind_buffer, 1); - } - if (buf == _sg.gl.cache.storage_buffer) { - _sg.gl.cache.storage_buffer = 0; - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); - _sg_stats_add(gl.num_bind_buffer, 1); - } - for (int stage = 0; stage < SG_NUM_SHADER_STAGES; stage++) { - for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { - if (buf == _sg.gl.cache.stage_storage_buffers[stage][i]) { - _sg.gl.cache.stage_storage_buffers[stage][i] = 0; - _sg.gl.cache.storage_buffer = 0; // not a bug! - const GLuint bind_index = _sg_gl_storagebuffer_bind_index(stage, i); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, bind_index, 0); - _sg_stats_add(gl.num_bind_buffer, 1); - } - } - } - if (buf == _sg.gl.cache.stored_vertex_buffer) { - _sg.gl.cache.stored_vertex_buffer = 0; - } - if (buf == _sg.gl.cache.stored_index_buffer) { - _sg.gl.cache.stored_index_buffer = 0; - } - if (buf == _sg.gl.cache.stored_storage_buffer) { - _sg.gl.cache.stored_storage_buffer = 0; - } - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - if (buf == _sg.gl.cache.attrs[i].gl_vbuf) { - _sg.gl.cache.attrs[i].gl_vbuf = 0; - } - } -} - -_SOKOL_PRIVATE void _sg_gl_cache_active_texture(GLenum texture) { - _SG_GL_CHECK_ERROR(); - if (_sg.gl.cache.cur_active_texture != texture) { - _sg.gl.cache.cur_active_texture = texture; - glActiveTexture(texture); - _sg_stats_add(gl.num_active_texture, 1); - } - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE void _sg_gl_cache_clear_texture_sampler_bindings(bool force) { - _SG_GL_CHECK_ERROR(); - for (int i = 0; (i < _SG_GL_TEXTURE_SAMPLER_CACHE_SIZE) && (i < _sg.limits.gl_max_combined_texture_image_units); i++) { - if (force || (_sg.gl.cache.texture_samplers[i].texture != 0)) { - GLenum gl_texture_unit = (GLenum) (GL_TEXTURE0 + i); - glActiveTexture(gl_texture_unit); - _sg_stats_add(gl.num_active_texture, 1); - glBindTexture(GL_TEXTURE_2D, 0); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - glBindTexture(GL_TEXTURE_3D, 0); - glBindTexture(GL_TEXTURE_2D_ARRAY, 0); - _sg_stats_add(gl.num_bind_texture, 4); - glBindSampler((GLuint)i, 0); - _sg_stats_add(gl.num_bind_sampler, 1); - _sg.gl.cache.texture_samplers[i].target = 0; - _sg.gl.cache.texture_samplers[i].texture = 0; - _sg.gl.cache.texture_samplers[i].sampler = 0; - _sg.gl.cache.cur_active_texture = gl_texture_unit; - } - } - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE void _sg_gl_cache_bind_texture_sampler(int slot_index, GLenum target, GLuint texture, GLuint sampler) { - /* it's valid to call this function with target=0 and/or texture=0 - target=0 will unbind the previous binding, texture=0 will clear - the new binding - */ - SOKOL_ASSERT((slot_index >= 0) && (slot_index < _SG_GL_TEXTURE_SAMPLER_CACHE_SIZE)); - if (slot_index >= _sg.limits.gl_max_combined_texture_image_units) { - return; - } - _SG_GL_CHECK_ERROR(); - _sg_gl_cache_texture_sampler_bind_slot* slot = &_sg.gl.cache.texture_samplers[slot_index]; - if ((slot->target != target) || (slot->texture != texture) || (slot->sampler != sampler)) { - _sg_gl_cache_active_texture((GLenum)(GL_TEXTURE0 + slot_index)); - // if the target has changed, clear the previous binding on that target - if ((target != slot->target) && (slot->target != 0)) { - glBindTexture(slot->target, 0); - _SG_GL_CHECK_ERROR(); - _sg_stats_add(gl.num_bind_texture, 1); - } - // apply new binding (can be 0 to unbind) - if (target != 0) { - glBindTexture(target, texture); - _SG_GL_CHECK_ERROR(); - _sg_stats_add(gl.num_bind_texture, 1); - } - // apply new sampler (can be 0 to unbind) - glBindSampler((GLuint)slot_index, sampler); - _SG_GL_CHECK_ERROR(); - _sg_stats_add(gl.num_bind_sampler, 1); - - slot->target = target; - slot->texture = texture; - slot->sampler = sampler; - } -} - -_SOKOL_PRIVATE void _sg_gl_cache_store_texture_sampler_binding(int slot_index) { - SOKOL_ASSERT((slot_index >= 0) && (slot_index < _SG_GL_TEXTURE_SAMPLER_CACHE_SIZE)); - _sg.gl.cache.stored_texture_sampler = _sg.gl.cache.texture_samplers[slot_index]; -} - -_SOKOL_PRIVATE void _sg_gl_cache_restore_texture_sampler_binding(int slot_index) { - SOKOL_ASSERT((slot_index >= 0) && (slot_index < _SG_GL_TEXTURE_SAMPLER_CACHE_SIZE)); - _sg_gl_cache_texture_sampler_bind_slot* slot = &_sg.gl.cache.stored_texture_sampler; - if (slot->texture != 0) { - // we only care about restoring valid ids - SOKOL_ASSERT(slot->target != 0); - _sg_gl_cache_bind_texture_sampler(slot_index, slot->target, slot->texture, slot->sampler); - slot->target = 0; - slot->texture = 0; - slot->sampler = 0; - } -} - -// called from _sg_gl_discard_texture() and _sg_gl_discard_sampler() -_SOKOL_PRIVATE void _sg_gl_cache_invalidate_texture_sampler(GLuint tex, GLuint smp) { - _SG_GL_CHECK_ERROR(); - for (int i = 0; i < _SG_GL_TEXTURE_SAMPLER_CACHE_SIZE; i++) { - _sg_gl_cache_texture_sampler_bind_slot* slot = &_sg.gl.cache.texture_samplers[i]; - if ((0 != slot->target) && ((tex == slot->texture) || (smp == slot->sampler))) { - _sg_gl_cache_active_texture((GLenum)(GL_TEXTURE0 + i)); - glBindTexture(slot->target, 0); - _SG_GL_CHECK_ERROR(); - _sg_stats_add(gl.num_bind_texture, 1); - glBindSampler((GLuint)i, 0); - _SG_GL_CHECK_ERROR(); - _sg_stats_add(gl.num_bind_sampler, 1); - slot->target = 0; - slot->texture = 0; - slot->sampler = 0; - } - } - if ((tex == _sg.gl.cache.stored_texture_sampler.texture) || (smp == _sg.gl.cache.stored_texture_sampler.sampler)) { - _sg.gl.cache.stored_texture_sampler.target = 0; - _sg.gl.cache.stored_texture_sampler.texture = 0; - _sg.gl.cache.stored_texture_sampler.sampler = 0; - } -} - -// called from _sg_gl_discard_shader() -_SOKOL_PRIVATE void _sg_gl_cache_invalidate_program(GLuint prog) { - if (prog == _sg.gl.cache.prog) { - _sg.gl.cache.prog = 0; - glUseProgram(0); - _sg_stats_add(gl.num_use_program, 1); - } -} - -// called from _sg_gl_discard_pipeline() -_SOKOL_PRIVATE void _sg_gl_cache_invalidate_pipeline(_sg_pipeline_t* pip) { - if (pip == _sg.gl.cache.cur_pipeline) { - _sg.gl.cache.cur_pipeline = 0; - _sg.gl.cache.cur_pipeline_id.id = SG_INVALID_ID; - } -} - -_SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) { - _SG_GL_CHECK_ERROR(); - glBindVertexArray(_sg.gl.vao); - _SG_GL_CHECK_ERROR(); - _sg_clear(&_sg.gl.cache, sizeof(_sg.gl.cache)); - _sg_gl_cache_clear_buffer_bindings(true); - _SG_GL_CHECK_ERROR(); - _sg_gl_cache_clear_texture_sampler_bindings(true); - _SG_GL_CHECK_ERROR(); - for (int i = 0; i < _sg.limits.max_vertex_attrs; i++) { - _sg_gl_attr_t* attr = &_sg.gl.cache.attrs[i].gl_attr; - attr->vb_index = -1; - attr->divisor = -1; - glDisableVertexAttribArray((GLuint)i); - _SG_GL_CHECK_ERROR(); - _sg_stats_add(gl.num_disable_vertex_attrib_array, 1); - } - _sg.gl.cache.cur_primitive_type = GL_TRIANGLES; - - // shader program - glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&_sg.gl.cache.prog); - _SG_GL_CHECK_ERROR(); - - // depth and stencil state - _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; - _sg.gl.cache.stencil.front.compare = SG_COMPAREFUNC_ALWAYS; - _sg.gl.cache.stencil.front.fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.front.depth_fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.front.pass_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.back.compare = SG_COMPAREFUNC_ALWAYS; - _sg.gl.cache.stencil.back.fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.back.depth_fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.back.pass_op = SG_STENCILOP_KEEP; - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glDepthMask(GL_FALSE); - glDisable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 0, 0); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilMask(0); - _sg_stats_add(gl.num_render_state, 7); - - // blend state - _sg.gl.cache.blend.src_factor_rgb = SG_BLENDFACTOR_ONE; - _sg.gl.cache.blend.dst_factor_rgb = SG_BLENDFACTOR_ZERO; - _sg.gl.cache.blend.op_rgb = SG_BLENDOP_ADD; - _sg.gl.cache.blend.src_factor_alpha = SG_BLENDFACTOR_ONE; - _sg.gl.cache.blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO; - _sg.gl.cache.blend.op_alpha = SG_BLENDOP_ADD; - glDisable(GL_BLEND); - glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); - glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); - _sg_stats_add(gl.num_render_state, 4); - - // standalone state - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; - } - _sg.gl.cache.cull_mode = SG_CULLMODE_NONE; - _sg.gl.cache.face_winding = SG_FACEWINDING_CW; - _sg.gl.cache.sample_count = 1; - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glPolygonOffset(0.0f, 0.0f); - glDisable(GL_POLYGON_OFFSET_FILL); - glDisable(GL_CULL_FACE); - glFrontFace(GL_CW); - glCullFace(GL_BACK); - glEnable(GL_SCISSOR_TEST); - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - glEnable(GL_DITHER); - glDisable(GL_POLYGON_OFFSET_FILL); - _sg_stats_add(gl.num_render_state, 10); - #if defined(SOKOL_GLCORE) - glEnable(GL_MULTISAMPLE); - glEnable(GL_PROGRAM_POINT_SIZE); - _sg_stats_add(gl.num_render_state, 2); - #endif -} - -_SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { - _SOKOL_UNUSED(desc); - - // assumes that _sg.gl is already zero-initialized - _sg.gl.valid = true; - - #if defined(_SOKOL_USE_WIN32_GL_LOADER) - _sg_gl_load_opengl(); - #endif - - // clear initial GL error state - #if defined(SOKOL_DEBUG) - while (glGetError() != GL_NO_ERROR); - #endif - #if defined(SOKOL_GLCORE) - _sg_gl_init_caps_glcore(); - #elif defined(SOKOL_GLES3) - _sg_gl_init_caps_gles3(); - #endif - - glGenVertexArrays(1, &_sg.gl.vao); - glBindVertexArray(_sg.gl.vao); - _SG_GL_CHECK_ERROR(); - // incoming texture data is generally expected to be packed tightly - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - #if defined(SOKOL_GLCORE) - // enable seamless cubemap sampling (only desktop GL) - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - #endif - _sg_gl_reset_state_cache(); -} - -_SOKOL_PRIVATE void _sg_gl_discard_backend(void) { - SOKOL_ASSERT(_sg.gl.valid); - if (_sg.gl.vao) { - glDeleteVertexArrays(1, &_sg.gl.vao); - } - #if defined(_SOKOL_USE_WIN32_GL_LOADER) - _sg_gl_unload_opengl(); - #endif - _sg.gl.valid = false; -} - -//-- GL backend resource creation and destruction ------------------------------ -_SOKOL_PRIVATE sg_resource_state _sg_gl_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { - SOKOL_ASSERT(buf && desc); - _SG_GL_CHECK_ERROR(); - buf->gl.injected = (0 != desc->gl_buffers[0]); - const GLenum gl_target = _sg_gl_buffer_target(buf->cmn.type); - const GLenum gl_usage = _sg_gl_usage(buf->cmn.usage); - for (int slot = 0; slot < buf->cmn.num_slots; slot++) { - GLuint gl_buf = 0; - if (buf->gl.injected) { - SOKOL_ASSERT(desc->gl_buffers[slot]); - gl_buf = desc->gl_buffers[slot]; - } else { - glGenBuffers(1, &gl_buf); - SOKOL_ASSERT(gl_buf); - _sg_gl_cache_store_buffer_binding(gl_target); - _sg_gl_cache_bind_buffer(gl_target, gl_buf); - glBufferData(gl_target, buf->cmn.size, 0, gl_usage); - if (buf->cmn.usage == SG_USAGE_IMMUTABLE) { - SOKOL_ASSERT(desc->data.ptr); - glBufferSubData(gl_target, 0, buf->cmn.size, desc->data.ptr); - } - _sg_gl_cache_restore_buffer_binding(gl_target); - } - buf->gl.buf[slot] = gl_buf; - } - _SG_GL_CHECK_ERROR(); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_gl_discard_buffer(_sg_buffer_t* buf) { - SOKOL_ASSERT(buf); - _SG_GL_CHECK_ERROR(); - for (int slot = 0; slot < buf->cmn.num_slots; slot++) { - if (buf->gl.buf[slot]) { - _sg_gl_cache_invalidate_buffer(buf->gl.buf[slot]); - if (!buf->gl.injected) { - glDeleteBuffers(1, &buf->gl.buf[slot]); - } - } - } - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE bool _sg_gl_supported_texture_format(sg_pixel_format fmt) { - const int fmt_index = (int) fmt; - SOKOL_ASSERT((fmt_index > SG_PIXELFORMAT_NONE) && (fmt_index < _SG_PIXELFORMAT_NUM)); - return _sg.formats[fmt_index].sample; -} - -_SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_image_desc* desc) { - SOKOL_ASSERT(img && desc); - _SG_GL_CHECK_ERROR(); - img->gl.injected = (0 != desc->gl_textures[0]); - - // check if texture format is support - if (!_sg_gl_supported_texture_format(img->cmn.pixel_format)) { - _SG_ERROR(GL_TEXTURE_FORMAT_NOT_SUPPORTED); - return SG_RESOURCESTATE_FAILED; - } - const GLenum gl_internal_format = _sg_gl_teximage_internal_format(img->cmn.pixel_format); - - // if this is a MSAA render target, a render buffer object will be created instead of a regulat texture - // (since GLES3 has no multisampled texture objects) - if (img->cmn.render_target && (img->cmn.sample_count > 1)) { - glGenRenderbuffers(1, &img->gl.msaa_render_buffer); - glBindRenderbuffer(GL_RENDERBUFFER, img->gl.msaa_render_buffer); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, img->cmn.sample_count, gl_internal_format, img->cmn.width, img->cmn.height); - } else if (img->gl.injected) { - img->gl.target = _sg_gl_texture_target(img->cmn.type); - // inject externally GL textures - for (int slot = 0; slot < img->cmn.num_slots; slot++) { - SOKOL_ASSERT(desc->gl_textures[slot]); - img->gl.tex[slot] = desc->gl_textures[slot]; - } - if (desc->gl_texture_target) { - img->gl.target = (GLenum)desc->gl_texture_target; - } - } else { - // create our own GL texture(s) - img->gl.target = _sg_gl_texture_target(img->cmn.type); - const GLenum gl_format = _sg_gl_teximage_format(img->cmn.pixel_format); - const bool is_compressed = _sg_is_compressed_pixel_format(img->cmn.pixel_format); - for (int slot = 0; slot < img->cmn.num_slots; slot++) { - glGenTextures(1, &img->gl.tex[slot]); - SOKOL_ASSERT(img->gl.tex[slot]); - _sg_gl_cache_store_texture_sampler_binding(0); - _sg_gl_cache_bind_texture_sampler(0, img->gl.target, img->gl.tex[slot], 0); - glTexParameteri(img->gl.target, GL_TEXTURE_MAX_LEVEL, img->cmn.num_mipmaps - 1); - - // NOTE: workaround for https://issues.chromium.org/issues/355605685 - // FIXME: on GLES3 and GL 4.3 (e.g. not macOS) the texture initialization - // should be rewritten to use glTexStorage + glTexSubImage - bool tex_storage_allocated = false; - #if defined(__EMSCRIPTEN__) - if (desc->data.subimage[0][0].ptr == 0) { - tex_storage_allocated = true; - if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) { - glTexStorage2D(img->gl.target, img->cmn.num_mipmaps, gl_internal_format, img->cmn.width, img->cmn.height); - } else if ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type)) { - glTexStorage3D(img->gl.target, img->cmn.num_mipmaps, gl_internal_format, img->cmn.width, img->cmn.height, img->cmn.num_slices); - } - } - #endif - if (!tex_storage_allocated) { - const int num_faces = img->cmn.type == SG_IMAGETYPE_CUBE ? 6 : 1; - int data_index = 0; - for (int face_index = 0; face_index < num_faces; face_index++) { - for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, data_index++) { - GLenum gl_img_target = img->gl.target; - if (SG_IMAGETYPE_CUBE == img->cmn.type) { - gl_img_target = _sg_gl_cubeface_target(face_index); - } - const GLvoid* data_ptr = desc->data.subimage[face_index][mip_index].ptr; - const int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); - const int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); - if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) { - if (is_compressed) { - const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size; - glCompressedTexImage2D(gl_img_target, mip_index, gl_internal_format, - mip_width, mip_height, 0, data_size, data_ptr); - } else { - const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); - glTexImage2D(gl_img_target, mip_index, (GLint)gl_internal_format, - mip_width, mip_height, 0, gl_format, gl_type, data_ptr); - } - } else if ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type)) { - int mip_depth = img->cmn.num_slices; - if (SG_IMAGETYPE_3D == img->cmn.type) { - mip_depth = _sg_miplevel_dim(mip_depth, mip_index); - } - if (is_compressed) { - const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size; - glCompressedTexImage3D(gl_img_target, mip_index, gl_internal_format, - mip_width, mip_height, mip_depth, 0, data_size, data_ptr); - } else { - const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); - glTexImage3D(gl_img_target, mip_index, (GLint)gl_internal_format, - mip_width, mip_height, mip_depth, 0, gl_format, gl_type, data_ptr); - } - } - } - } - } - _sg_gl_cache_restore_texture_sampler_binding(0); - } - } - _SG_GL_CHECK_ERROR(); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_gl_discard_image(_sg_image_t* img) { - SOKOL_ASSERT(img); - _SG_GL_CHECK_ERROR(); - for (int slot = 0; slot < img->cmn.num_slots; slot++) { - if (img->gl.tex[slot]) { - _sg_gl_cache_invalidate_texture_sampler(img->gl.tex[slot], 0); - if (!img->gl.injected) { - glDeleteTextures(1, &img->gl.tex[slot]); - } - } - } - if (img->gl.msaa_render_buffer) { - glDeleteRenderbuffers(1, &img->gl.msaa_render_buffer); - } - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE sg_resource_state _sg_gl_create_sampler(_sg_sampler_t* smp, const sg_sampler_desc* desc) { - SOKOL_ASSERT(smp && desc); - _SG_GL_CHECK_ERROR(); - smp->gl.injected = (0 != desc->gl_sampler); - if (smp->gl.injected) { - smp->gl.smp = (GLuint) desc->gl_sampler; - } else { - glGenSamplers(1, &smp->gl.smp); - SOKOL_ASSERT(smp->gl.smp); - - const GLenum gl_min_filter = _sg_gl_min_filter(smp->cmn.min_filter, smp->cmn.mipmap_filter); - const GLenum gl_mag_filter = _sg_gl_mag_filter(smp->cmn.mag_filter); - glSamplerParameteri(smp->gl.smp, GL_TEXTURE_MIN_FILTER, (GLint)gl_min_filter); - glSamplerParameteri(smp->gl.smp, GL_TEXTURE_MAG_FILTER, (GLint)gl_mag_filter); - // GL spec has strange defaults for mipmap min/max lod: -1000 to +1000 - const float min_lod = _sg_clamp(desc->min_lod, 0.0f, 1000.0f); - const float max_lod = _sg_clamp(desc->max_lod, 0.0f, 1000.0f); - glSamplerParameterf(smp->gl.smp, GL_TEXTURE_MIN_LOD, min_lod); - glSamplerParameterf(smp->gl.smp, GL_TEXTURE_MAX_LOD, max_lod); - glSamplerParameteri(smp->gl.smp, GL_TEXTURE_WRAP_S, (GLint)_sg_gl_wrap(smp->cmn.wrap_u)); - glSamplerParameteri(smp->gl.smp, GL_TEXTURE_WRAP_T, (GLint)_sg_gl_wrap(smp->cmn.wrap_v)); - glSamplerParameteri(smp->gl.smp, GL_TEXTURE_WRAP_R, (GLint)_sg_gl_wrap(smp->cmn.wrap_w)); - #if defined(SOKOL_GLCORE) - float border[4]; - switch (smp->cmn.border_color) { - case SG_BORDERCOLOR_TRANSPARENT_BLACK: - border[0] = 0.0f; border[1] = 0.0f; border[2] = 0.0f; border[3] = 0.0f; - break; - case SG_BORDERCOLOR_OPAQUE_WHITE: - border[0] = 1.0f; border[1] = 1.0f; border[2] = 1.0f; border[3] = 1.0f; - break; - default: - border[0] = 0.0f; border[1] = 0.0f; border[2] = 0.0f; border[3] = 1.0f; - break; - } - glSamplerParameterfv(smp->gl.smp, GL_TEXTURE_BORDER_COLOR, border); - #endif - if (smp->cmn.compare != SG_COMPAREFUNC_NEVER) { - glSamplerParameteri(smp->gl.smp, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glSamplerParameteri(smp->gl.smp, GL_TEXTURE_COMPARE_FUNC, (GLint)_sg_gl_compare_func(smp->cmn.compare)); - } else { - glSamplerParameteri(smp->gl.smp, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - if (_sg.gl.ext_anisotropic && (smp->cmn.max_anisotropy > 1)) { - GLint max_aniso = (GLint) smp->cmn.max_anisotropy; - if (max_aniso > _sg.gl.max_anisotropy) { - max_aniso = _sg.gl.max_anisotropy; - } - glSamplerParameteri(smp->gl.smp, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso); - } - } - _SG_GL_CHECK_ERROR(); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_gl_discard_sampler(_sg_sampler_t* smp) { - SOKOL_ASSERT(smp); - _SG_GL_CHECK_ERROR(); - _sg_gl_cache_invalidate_texture_sampler(0, smp->gl.smp); - if (!smp->gl.injected) { - glDeleteSamplers(1, &smp->gl.smp); - } - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE GLuint _sg_gl_compile_shader(sg_shader_stage stage, const char* src) { - SOKOL_ASSERT(src); - _SG_GL_CHECK_ERROR(); - GLuint gl_shd = glCreateShader(_sg_gl_shader_stage(stage)); - glShaderSource(gl_shd, 1, &src, 0); - glCompileShader(gl_shd); - GLint compile_status = 0; - glGetShaderiv(gl_shd, GL_COMPILE_STATUS, &compile_status); - if (!compile_status) { - // compilation failed, log error and delete shader - GLint log_len = 0; - glGetShaderiv(gl_shd, GL_INFO_LOG_LENGTH, &log_len); - if (log_len > 0) { - GLchar* log_buf = (GLchar*) _sg_malloc((size_t)log_len); - glGetShaderInfoLog(gl_shd, log_len, &log_len, log_buf); - _SG_ERROR(GL_SHADER_COMPILATION_FAILED); - _SG_LOGMSG(GL_SHADER_COMPILATION_FAILED, log_buf); - _sg_free(log_buf); - } - glDeleteShader(gl_shd); - gl_shd = 0; - } - _SG_GL_CHECK_ERROR(); - return gl_shd; -} - -_SOKOL_PRIVATE sg_resource_state _sg_gl_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { - SOKOL_ASSERT(shd && desc); - SOKOL_ASSERT(!shd->gl.prog); - _SG_GL_CHECK_ERROR(); - - // copy the optional vertex attribute names over - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - _sg_strcpy(&shd->gl.attrs[i].name, desc->attrs[i].name); - } - - GLuint gl_vs = _sg_gl_compile_shader(SG_SHADERSTAGE_VS, desc->vs.source); - GLuint gl_fs = _sg_gl_compile_shader(SG_SHADERSTAGE_FS, desc->fs.source); - if (!(gl_vs && gl_fs)) { - return SG_RESOURCESTATE_FAILED; - } - GLuint gl_prog = glCreateProgram(); - glAttachShader(gl_prog, gl_vs); - glAttachShader(gl_prog, gl_fs); - glLinkProgram(gl_prog); - glDeleteShader(gl_vs); - glDeleteShader(gl_fs); - _SG_GL_CHECK_ERROR(); - - GLint link_status; - glGetProgramiv(gl_prog, GL_LINK_STATUS, &link_status); - if (!link_status) { - GLint log_len = 0; - glGetProgramiv(gl_prog, GL_INFO_LOG_LENGTH, &log_len); - if (log_len > 0) { - GLchar* log_buf = (GLchar*) _sg_malloc((size_t)log_len); - glGetProgramInfoLog(gl_prog, log_len, &log_len, log_buf); - _SG_ERROR(GL_SHADER_LINKING_FAILED); - _SG_LOGMSG(GL_SHADER_LINKING_FAILED, log_buf); - _sg_free(log_buf); - } - glDeleteProgram(gl_prog); - return SG_RESOURCESTATE_FAILED; - } - shd->gl.prog = gl_prog; - - // resolve uniforms - _SG_GL_CHECK_ERROR(); - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS)? &desc->vs : &desc->fs; - const _sg_shader_stage_t* stage = &shd->cmn.stage[stage_index]; - _sg_gl_shader_stage_t* gl_stage = &shd->gl.stage[stage_index]; - for (int ub_index = 0; ub_index < stage->num_uniform_blocks; ub_index++) { - const sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index]; - SOKOL_ASSERT(ub_desc->size > 0); - _sg_gl_uniform_block_t* ub = &gl_stage->uniform_blocks[ub_index]; - SOKOL_ASSERT(ub->num_uniforms == 0); - uint32_t cur_uniform_offset = 0; - for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) { - const sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index]; - if (u_desc->type == SG_UNIFORMTYPE_INVALID) { - break; - } - const uint32_t u_align = _sg_uniform_alignment(u_desc->type, u_desc->array_count, ub_desc->layout); - const uint32_t u_size = _sg_uniform_size(u_desc->type, u_desc->array_count, ub_desc->layout); - cur_uniform_offset = _sg_align_u32(cur_uniform_offset, u_align); - _sg_gl_uniform_t* u = &ub->uniforms[u_index]; - u->type = u_desc->type; - u->count = (uint16_t) u_desc->array_count; - u->offset = (uint16_t) cur_uniform_offset; - cur_uniform_offset += u_size; - if (u_desc->name) { - u->gl_loc = glGetUniformLocation(gl_prog, u_desc->name); - } else { - u->gl_loc = u_index; - } - ub->num_uniforms++; - } - if (ub_desc->layout == SG_UNIFORMLAYOUT_STD140) { - cur_uniform_offset = _sg_align_u32(cur_uniform_offset, 16); - } - SOKOL_ASSERT(ub_desc->size == (size_t)cur_uniform_offset); - _SOKOL_UNUSED(cur_uniform_offset); - } - } - - // resolve combined image samplers - _SG_GL_CHECK_ERROR(); - GLuint cur_prog = 0; - glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&cur_prog); - glUseProgram(gl_prog); - int gl_tex_slot = 0; - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS)? &desc->vs : &desc->fs; - const _sg_shader_stage_t* stage = &shd->cmn.stage[stage_index]; - _sg_gl_shader_stage_t* gl_stage = &shd->gl.stage[stage_index]; - for (int img_smp_index = 0; img_smp_index < stage->num_image_samplers; img_smp_index++) { - const sg_shader_image_sampler_pair_desc* img_smp_desc = &stage_desc->image_sampler_pairs[img_smp_index]; - _sg_gl_shader_image_sampler_t* gl_img_smp = &gl_stage->image_samplers[img_smp_index]; - SOKOL_ASSERT(img_smp_desc->glsl_name); - GLint gl_loc = glGetUniformLocation(gl_prog, img_smp_desc->glsl_name); - if (gl_loc != -1) { - gl_img_smp->gl_tex_slot = gl_tex_slot++; - glUniform1i(gl_loc, gl_img_smp->gl_tex_slot); - } else { - gl_img_smp->gl_tex_slot = -1; - _SG_ERROR(GL_TEXTURE_NAME_NOT_FOUND_IN_SHADER); - _SG_LOGMSG(GL_TEXTURE_NAME_NOT_FOUND_IN_SHADER, img_smp_desc->glsl_name); - } - } - } - // it's legal to call glUseProgram with 0 - glUseProgram(cur_prog); - _SG_GL_CHECK_ERROR(); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_gl_discard_shader(_sg_shader_t* shd) { - SOKOL_ASSERT(shd); - _SG_GL_CHECK_ERROR(); - if (shd->gl.prog) { - _sg_gl_cache_invalidate_program(shd->gl.prog); - glDeleteProgram(shd->gl.prog); - } - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE sg_resource_state _sg_gl_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { - SOKOL_ASSERT(pip && shd && desc); - SOKOL_ASSERT((pip->shader == 0) && (pip->cmn.shader_id.id != SG_INVALID_ID)); - SOKOL_ASSERT(desc->shader.id == shd->slot.id); - SOKOL_ASSERT(shd->gl.prog); - pip->shader = shd; - pip->gl.primitive_type = desc->primitive_type; - pip->gl.depth = desc->depth; - pip->gl.stencil = desc->stencil; - // FIXME: blend color and write mask per draw-buffer-attachment (requires GL4) - pip->gl.blend = desc->colors[0].blend; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - pip->gl.color_write_mask[i] = desc->colors[i].write_mask; - } - pip->gl.cull_mode = desc->cull_mode; - pip->gl.face_winding = desc->face_winding; - pip->gl.sample_count = desc->sample_count; - pip->gl.alpha_to_coverage_enabled = desc->alpha_to_coverage_enabled; - - // resolve vertex attributes - for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { - pip->gl.attrs[attr_index].vb_index = -1; - } - for (int attr_index = 0; attr_index < _sg.limits.max_vertex_attrs; attr_index++) { - const sg_vertex_attr_state* a_state = &desc->layout.attrs[attr_index]; - if (a_state->format == SG_VERTEXFORMAT_INVALID) { - break; - } - SOKOL_ASSERT(a_state->buffer_index < SG_MAX_VERTEX_BUFFERS); - const sg_vertex_buffer_layout_state* l_state = &desc->layout.buffers[a_state->buffer_index]; - const sg_vertex_step step_func = l_state->step_func; - const int step_rate = l_state->step_rate; - GLint attr_loc = attr_index; - if (!_sg_strempty(&shd->gl.attrs[attr_index].name)) { - attr_loc = glGetAttribLocation(pip->shader->gl.prog, _sg_strptr(&shd->gl.attrs[attr_index].name)); - } - SOKOL_ASSERT(attr_loc < (GLint)_sg.limits.max_vertex_attrs); - if (attr_loc != -1) { - _sg_gl_attr_t* gl_attr = &pip->gl.attrs[attr_loc]; - SOKOL_ASSERT(gl_attr->vb_index == -1); - gl_attr->vb_index = (int8_t) a_state->buffer_index; - if (step_func == SG_VERTEXSTEP_PER_VERTEX) { - gl_attr->divisor = 0; - } else { - gl_attr->divisor = (int8_t) step_rate; - pip->cmn.use_instanced_draw = true; - } - SOKOL_ASSERT(l_state->stride > 0); - gl_attr->stride = (uint8_t) l_state->stride; - gl_attr->offset = a_state->offset; - gl_attr->size = (uint8_t) _sg_gl_vertexformat_size(a_state->format); - gl_attr->type = _sg_gl_vertexformat_type(a_state->format); - gl_attr->normalized = _sg_gl_vertexformat_normalized(a_state->format); - pip->cmn.vertex_buffer_layout_active[a_state->buffer_index] = true; - } else { - _SG_ERROR(GL_VERTEX_ATTRIBUTE_NOT_FOUND_IN_SHADER); - _SG_LOGMSG(GL_VERTEX_ATTRIBUTE_NOT_FOUND_IN_SHADER, _sg_strptr(&shd->gl.attrs[attr_index].name)); - } - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_gl_discard_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - _sg_gl_cache_invalidate_pipeline(pip); -} - -_SOKOL_PRIVATE void _sg_gl_fb_attach_texture(const _sg_gl_attachment_t* gl_att, const _sg_attachment_common_t* cmn_att, GLenum gl_att_type) { - const _sg_image_t* img = gl_att->image; - SOKOL_ASSERT(img); - const GLuint gl_tex = img->gl.tex[0]; - SOKOL_ASSERT(gl_tex); - const GLuint gl_target = img->gl.target; - SOKOL_ASSERT(gl_target); - const int mip_level = cmn_att->mip_level; - const int slice = cmn_att->slice; - switch (img->cmn.type) { - case SG_IMAGETYPE_2D: - glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att_type, gl_target, gl_tex, mip_level); - break; - case SG_IMAGETYPE_CUBE: - glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att_type, _sg_gl_cubeface_target(slice), gl_tex, mip_level); - break; - default: - glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_att_type, gl_tex, mip_level, slice); - break; - } -} - -_SOKOL_PRIVATE GLenum _sg_gl_depth_stencil_attachment_type(const _sg_gl_attachment_t* ds_att) { - const _sg_image_t* img = ds_att->image; - SOKOL_ASSERT(img); - if (_sg_is_depth_stencil_format(img->cmn.pixel_format)) { - return GL_DEPTH_STENCIL_ATTACHMENT; - } else { - return GL_DEPTH_ATTACHMENT; - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_gl_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_image, const sg_attachments_desc* desc) { - SOKOL_ASSERT(atts && desc); - SOKOL_ASSERT(color_images && resolve_images); - _SG_GL_CHECK_ERROR(); - - // copy image pointers - for (int i = 0; i < atts->cmn.num_colors; i++) { - const sg_attachment_desc* color_desc = &desc->colors[i]; - _SOKOL_UNUSED(color_desc); - SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == atts->gl.colors[i].image); - SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); - atts->gl.colors[i].image = color_images[i]; - - const sg_attachment_desc* resolve_desc = &desc->resolves[i]; - if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == atts->gl.resolves[i].image); - SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); - SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); - atts->gl.resolves[i].image = resolve_images[i]; - } - } - SOKOL_ASSERT(0 == atts->gl.depth_stencil.image); - const sg_attachment_desc* ds_desc = &desc->depth_stencil; - if (ds_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(ds_image && (ds_image->slot.id == ds_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_image->cmn.pixel_format)); - atts->gl.depth_stencil.image = ds_image; - } - - // store current framebuffer binding (restored at end of function) - GLuint gl_orig_fb; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&gl_orig_fb); - - // create a framebuffer object - glGenFramebuffers(1, &atts->gl.fb); - glBindFramebuffer(GL_FRAMEBUFFER, atts->gl.fb); - - // attach color attachments to framebuffer - for (int i = 0; i < atts->cmn.num_colors; i++) { - const _sg_image_t* color_img = atts->gl.colors[i].image; - SOKOL_ASSERT(color_img); - const GLuint gl_msaa_render_buffer = color_img->gl.msaa_render_buffer; - if (gl_msaa_render_buffer) { - glFramebufferRenderbuffer(GL_FRAMEBUFFER, (GLenum)(GL_COLOR_ATTACHMENT0+i), GL_RENDERBUFFER, gl_msaa_render_buffer); - } else { - const GLenum gl_att_type = (GLenum)(GL_COLOR_ATTACHMENT0 + i); - _sg_gl_fb_attach_texture(&atts->gl.colors[i], &atts->cmn.colors[i], gl_att_type); - } - } - // attach depth-stencil attachment - if (atts->gl.depth_stencil.image) { - const GLenum gl_att = _sg_gl_depth_stencil_attachment_type(&atts->gl.depth_stencil); - const _sg_image_t* ds_img = atts->gl.depth_stencil.image; - const GLuint gl_msaa_render_buffer = ds_img->gl.msaa_render_buffer; - if (gl_msaa_render_buffer) { - glFramebufferRenderbuffer(GL_FRAMEBUFFER, gl_att, GL_RENDERBUFFER, gl_msaa_render_buffer); - } else { - const GLenum gl_att_type = _sg_gl_depth_stencil_attachment_type(&atts->gl.depth_stencil); - _sg_gl_fb_attach_texture(&atts->gl.depth_stencil, &atts->cmn.depth_stencil, gl_att_type); - } - } - - // check if framebuffer is complete - { - const GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (fb_status != GL_FRAMEBUFFER_COMPLETE) { - switch (fb_status) { - case GL_FRAMEBUFFER_UNDEFINED: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_UNDEFINED); - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_INCOMPLETE_ATTACHMENT); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_INCOMPLETE_MISSING_ATTACHMENT); - break; - case GL_FRAMEBUFFER_UNSUPPORTED: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_UNSUPPORTED); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_INCOMPLETE_MULTISAMPLE); - break; - default: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_UNKNOWN); - break; - } - return SG_RESOURCESTATE_FAILED; - } - } - - // setup color attachments for the framebuffer - static const GLenum gl_draw_bufs[SG_MAX_COLOR_ATTACHMENTS] = { - GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, - GL_COLOR_ATTACHMENT2, - GL_COLOR_ATTACHMENT3 - }; - glDrawBuffers(atts->cmn.num_colors, gl_draw_bufs); - - // create MSAA resolve framebuffers if necessary - for (int i = 0; i < atts->cmn.num_colors; i++) { - _sg_gl_attachment_t* gl_resolve_att = &atts->gl.resolves[i]; - if (gl_resolve_att->image) { - _sg_attachment_common_t* cmn_resolve_att = &atts->cmn.resolves[i]; - SOKOL_ASSERT(0 == atts->gl.msaa_resolve_framebuffer[i]); - glGenFramebuffers(1, &atts->gl.msaa_resolve_framebuffer[i]); - glBindFramebuffer(GL_FRAMEBUFFER, atts->gl.msaa_resolve_framebuffer[i]); - _sg_gl_fb_attach_texture(gl_resolve_att, cmn_resolve_att, GL_COLOR_ATTACHMENT0); - // check if framebuffer is complete - const GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (fb_status != GL_FRAMEBUFFER_COMPLETE) { - switch (fb_status) { - case GL_FRAMEBUFFER_UNDEFINED: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_UNDEFINED); - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_INCOMPLETE_ATTACHMENT); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_INCOMPLETE_MISSING_ATTACHMENT); - break; - case GL_FRAMEBUFFER_UNSUPPORTED: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_UNSUPPORTED); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_INCOMPLETE_MULTISAMPLE); - break; - default: - _SG_ERROR(GL_FRAMEBUFFER_STATUS_UNKNOWN); - break; - } - return SG_RESOURCESTATE_FAILED; - } - // setup color attachments for the framebuffer - glDrawBuffers(1, &gl_draw_bufs[0]); - } - } - - // restore original framebuffer binding - glBindFramebuffer(GL_FRAMEBUFFER, gl_orig_fb); - _SG_GL_CHECK_ERROR(); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_gl_discard_attachments(_sg_attachments_t* atts) { - SOKOL_ASSERT(atts); - _SG_GL_CHECK_ERROR(); - if (0 != atts->gl.fb) { - glDeleteFramebuffers(1, &atts->gl.fb); - } - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (atts->gl.msaa_resolve_framebuffer[i]) { - glDeleteFramebuffers(1, &atts->gl.msaa_resolve_framebuffer[i]); - } - } - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE _sg_image_t* _sg_gl_attachments_color_image(const _sg_attachments_t* atts, int index) { - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return atts->gl.colors[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_gl_attachments_resolve_image(const _sg_attachments_t* atts, int index) { - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return atts->gl.resolves[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_gl_attachments_ds_image(const _sg_attachments_t* atts) { - SOKOL_ASSERT(atts); - return atts->gl.depth_stencil.image; -} - -_SOKOL_PRIVATE void _sg_gl_begin_pass(const sg_pass* pass) { - // FIXME: what if a texture used as render target is still bound, should we - // unbind all currently bound textures in begin pass? - SOKOL_ASSERT(pass); - _SG_GL_CHECK_ERROR(); - const _sg_attachments_t* atts = _sg.cur_pass.atts; - const sg_swapchain* swapchain = &pass->swapchain; - const sg_pass_action* action = &pass->action; - - // bind the render pass framebuffer - // - // FIXME: Disabling SRGB conversion for the default framebuffer is - // a crude hack to make behaviour for sRGB render target textures - // identical with the Metal and D3D11 swapchains created by sokol-app. - // - // This will need a cleaner solution (e.g. allowing to configure - // sokol_app.h with an sRGB or RGB framebuffer. - if (atts) { - // offscreen pass - SOKOL_ASSERT(atts->gl.fb); - #if defined(SOKOL_GLCORE) - glEnable(GL_FRAMEBUFFER_SRGB); - #endif - glBindFramebuffer(GL_FRAMEBUFFER, atts->gl.fb); - } else { - // default pass - #if defined(SOKOL_GLCORE) - glDisable(GL_FRAMEBUFFER_SRGB); - #endif - // NOTE: on some platforms, the default framebuffer of a context - // is null, so we can't actually assert here that the - // framebuffer has been provided - glBindFramebuffer(GL_FRAMEBUFFER, swapchain->gl.framebuffer); - } - glViewport(0, 0, _sg.cur_pass.width, _sg.cur_pass.height); - glScissor(0, 0, _sg.cur_pass.width, _sg.cur_pass.height); - - // number of color attachments - const int num_color_atts = atts ? atts->cmn.num_colors : 1; - - // clear color and depth-stencil attachments if needed - bool clear_any_color = false; - for (int i = 0; i < num_color_atts; i++) { - if (SG_LOADACTION_CLEAR == action->colors[i].load_action) { - clear_any_color = true; - break; - } - } - const bool clear_depth = (action->depth.load_action == SG_LOADACTION_CLEAR); - const bool clear_stencil = (action->stencil.load_action == SG_LOADACTION_CLEAR); - - bool need_pip_cache_flush = false; - if (clear_any_color) { - bool need_color_mask_flush = false; - // NOTE: not a bug to iterate over all possible color attachments - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (SG_COLORMASK_RGBA != _sg.gl.cache.color_write_mask[i]) { - need_pip_cache_flush = true; - need_color_mask_flush = true; - _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; - } - } - if (need_color_mask_flush) { - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - } - } - if (clear_depth) { - if (!_sg.gl.cache.depth.write_enabled) { - need_pip_cache_flush = true; - _sg.gl.cache.depth.write_enabled = true; - glDepthMask(GL_TRUE); - } - if (_sg.gl.cache.depth.compare != SG_COMPAREFUNC_ALWAYS) { - need_pip_cache_flush = true; - _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; - glDepthFunc(GL_ALWAYS); - } - } - if (clear_stencil) { - if (_sg.gl.cache.stencil.write_mask != 0xFF) { - need_pip_cache_flush = true; - _sg.gl.cache.stencil.write_mask = 0xFF; - glStencilMask(0xFF); - } - } - if (need_pip_cache_flush) { - // we messed with the state cache directly, need to clear cached - // pipeline to force re-evaluation in next sg_apply_pipeline() - _sg.gl.cache.cur_pipeline = 0; - _sg.gl.cache.cur_pipeline_id.id = SG_INVALID_ID; - } - for (int i = 0; i < num_color_atts; i++) { - if (action->colors[i].load_action == SG_LOADACTION_CLEAR) { - glClearBufferfv(GL_COLOR, i, &action->colors[i].clear_value.r); - } - } - if ((atts == 0) || (atts->gl.depth_stencil.image)) { - if (clear_depth && clear_stencil) { - glClearBufferfi(GL_DEPTH_STENCIL, 0, action->depth.clear_value, action->stencil.clear_value); - } else if (clear_depth) { - glClearBufferfv(GL_DEPTH, 0, &action->depth.clear_value); - } else if (clear_stencil) { - GLint val = (GLint) action->stencil.clear_value; - glClearBufferiv(GL_STENCIL, 0, &val); - } - } - // keep store actions for end-pass - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - _sg.gl.color_store_actions[i] = action->colors[i].store_action; - } - _sg.gl.depth_store_action = action->depth.store_action; - _sg.gl.stencil_store_action = action->stencil.store_action; - - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE void _sg_gl_end_pass(void) { - _SG_GL_CHECK_ERROR(); - - if (_sg.cur_pass.atts) { - const _sg_attachments_t* atts = _sg.cur_pass.atts; - SOKOL_ASSERT(atts->slot.id == _sg.cur_pass.atts_id.id); - bool fb_read_bound = false; - bool fb_draw_bound = false; - const int num_color_atts = atts->cmn.num_colors; - for (int i = 0; i < num_color_atts; i++) { - // perform MSAA resolve if needed - if (atts->gl.msaa_resolve_framebuffer[i] != 0) { - if (!fb_read_bound) { - SOKOL_ASSERT(atts->gl.fb); - glBindFramebuffer(GL_READ_FRAMEBUFFER, atts->gl.fb); - fb_read_bound = true; - } - const int w = atts->gl.colors[i].image->cmn.width; - const int h = atts->gl.colors[i].image->cmn.height; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, atts->gl.msaa_resolve_framebuffer[i]); - glReadBuffer((GLenum)(GL_COLOR_ATTACHMENT0 + i)); - glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); - fb_draw_bound = true; - } - } - - // invalidate framebuffers - _SOKOL_UNUSED(fb_draw_bound); - #if defined(SOKOL_GLES3) - // need to restore framebuffer binding before invalidate if the MSAA resolve had changed the binding - if (fb_draw_bound) { - glBindFramebuffer(GL_FRAMEBUFFER, atts->gl.fb); - } - GLenum invalidate_atts[SG_MAX_COLOR_ATTACHMENTS + 2] = { 0 }; - int att_index = 0; - for (int i = 0; i < num_color_atts; i++) { - if (_sg.gl.color_store_actions[i] == SG_STOREACTION_DONTCARE) { - invalidate_atts[att_index++] = (GLenum)(GL_COLOR_ATTACHMENT0 + i); - } - } - if ((_sg.gl.depth_store_action == SG_STOREACTION_DONTCARE) && (_sg.cur_pass.atts->cmn.depth_stencil.image_id.id != SG_INVALID_ID)) { - invalidate_atts[att_index++] = GL_DEPTH_ATTACHMENT; - } - if ((_sg.gl.stencil_store_action == SG_STOREACTION_DONTCARE) && (_sg.cur_pass.atts->cmn.depth_stencil.image_id.id != SG_INVALID_ID)) { - invalidate_atts[att_index++] = GL_STENCIL_ATTACHMENT; - } - if (att_index > 0) { - glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, att_index, invalidate_atts); - } - #endif - } - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE void _sg_gl_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { - y = origin_top_left ? (_sg.cur_pass.height - (y+h)) : y; - glViewport(x, y, w, h); -} - -_SOKOL_PRIVATE void _sg_gl_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - y = origin_top_left ? (_sg.cur_pass.height - (y+h)) : y; - glScissor(x, y, w, h); -} - -_SOKOL_PRIVATE void _sg_gl_apply_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); - _SG_GL_CHECK_ERROR(); - if ((_sg.gl.cache.cur_pipeline != pip) || (_sg.gl.cache.cur_pipeline_id.id != pip->slot.id)) { - _sg.gl.cache.cur_pipeline = pip; - _sg.gl.cache.cur_pipeline_id.id = pip->slot.id; - _sg.gl.cache.cur_primitive_type = _sg_gl_primitive_type(pip->gl.primitive_type); - _sg.gl.cache.cur_index_type = _sg_gl_index_type(pip->cmn.index_type); - - // update depth state - { - const sg_depth_state* state_ds = &pip->gl.depth; - sg_depth_state* cache_ds = &_sg.gl.cache.depth; - if (state_ds->compare != cache_ds->compare) { - cache_ds->compare = state_ds->compare; - glDepthFunc(_sg_gl_compare_func(state_ds->compare)); - _sg_stats_add(gl.num_render_state, 1); - } - if (state_ds->write_enabled != cache_ds->write_enabled) { - cache_ds->write_enabled = state_ds->write_enabled; - glDepthMask(state_ds->write_enabled); - _sg_stats_add(gl.num_render_state, 1); - } - if (!_sg_fequal(state_ds->bias, cache_ds->bias, 0.000001f) || - !_sg_fequal(state_ds->bias_slope_scale, cache_ds->bias_slope_scale, 0.000001f)) - { - /* according to ANGLE's D3D11 backend: - D3D11 SlopeScaledDepthBias ==> GL polygonOffsetFactor - D3D11 DepthBias ==> GL polygonOffsetUnits - DepthBiasClamp has no meaning on GL - */ - cache_ds->bias = state_ds->bias; - cache_ds->bias_slope_scale = state_ds->bias_slope_scale; - glPolygonOffset(state_ds->bias_slope_scale, state_ds->bias); - _sg_stats_add(gl.num_render_state, 1); - bool po_enabled = true; - if (_sg_fequal(state_ds->bias, 0.0f, 0.000001f) && - _sg_fequal(state_ds->bias_slope_scale, 0.0f, 0.000001f)) - { - po_enabled = false; - } - if (po_enabled != _sg.gl.cache.polygon_offset_enabled) { - _sg.gl.cache.polygon_offset_enabled = po_enabled; - if (po_enabled) { - glEnable(GL_POLYGON_OFFSET_FILL); - } else { - glDisable(GL_POLYGON_OFFSET_FILL); - } - _sg_stats_add(gl.num_render_state, 1); - } - } - } - - // update stencil state - { - const sg_stencil_state* state_ss = &pip->gl.stencil; - sg_stencil_state* cache_ss = &_sg.gl.cache.stencil; - if (state_ss->enabled != cache_ss->enabled) { - cache_ss->enabled = state_ss->enabled; - if (state_ss->enabled) { - glEnable(GL_STENCIL_TEST); - } else { - glDisable(GL_STENCIL_TEST); - } - _sg_stats_add(gl.num_render_state, 1); - } - if (state_ss->write_mask != cache_ss->write_mask) { - cache_ss->write_mask = state_ss->write_mask; - glStencilMask(state_ss->write_mask); - _sg_stats_add(gl.num_render_state, 1); - } - for (int i = 0; i < 2; i++) { - const sg_stencil_face_state* state_sfs = (i==0)? &state_ss->front : &state_ss->back; - sg_stencil_face_state* cache_sfs = (i==0)? &cache_ss->front : &cache_ss->back; - GLenum gl_face = (i==0)? GL_FRONT : GL_BACK; - if ((state_sfs->compare != cache_sfs->compare) || - (state_ss->read_mask != cache_ss->read_mask) || - (state_ss->ref != cache_ss->ref)) - { - cache_sfs->compare = state_sfs->compare; - glStencilFuncSeparate(gl_face, - _sg_gl_compare_func(state_sfs->compare), - state_ss->ref, - state_ss->read_mask); - _sg_stats_add(gl.num_render_state, 1); - } - if ((state_sfs->fail_op != cache_sfs->fail_op) || - (state_sfs->depth_fail_op != cache_sfs->depth_fail_op) || - (state_sfs->pass_op != cache_sfs->pass_op)) - { - cache_sfs->fail_op = state_sfs->fail_op; - cache_sfs->depth_fail_op = state_sfs->depth_fail_op; - cache_sfs->pass_op = state_sfs->pass_op; - glStencilOpSeparate(gl_face, - _sg_gl_stencil_op(state_sfs->fail_op), - _sg_gl_stencil_op(state_sfs->depth_fail_op), - _sg_gl_stencil_op(state_sfs->pass_op)); - _sg_stats_add(gl.num_render_state, 1); - } - } - cache_ss->read_mask = state_ss->read_mask; - cache_ss->ref = state_ss->ref; - } - - if (pip->cmn.color_count > 0) { - // update blend state - // FIXME: separate blend state per color attachment not support, needs GL4 - const sg_blend_state* state_bs = &pip->gl.blend; - sg_blend_state* cache_bs = &_sg.gl.cache.blend; - if (state_bs->enabled != cache_bs->enabled) { - cache_bs->enabled = state_bs->enabled; - if (state_bs->enabled) { - glEnable(GL_BLEND); - } else { - glDisable(GL_BLEND); - } - _sg_stats_add(gl.num_render_state, 1); - } - if ((state_bs->src_factor_rgb != cache_bs->src_factor_rgb) || - (state_bs->dst_factor_rgb != cache_bs->dst_factor_rgb) || - (state_bs->src_factor_alpha != cache_bs->src_factor_alpha) || - (state_bs->dst_factor_alpha != cache_bs->dst_factor_alpha)) - { - cache_bs->src_factor_rgb = state_bs->src_factor_rgb; - cache_bs->dst_factor_rgb = state_bs->dst_factor_rgb; - cache_bs->src_factor_alpha = state_bs->src_factor_alpha; - cache_bs->dst_factor_alpha = state_bs->dst_factor_alpha; - glBlendFuncSeparate(_sg_gl_blend_factor(state_bs->src_factor_rgb), - _sg_gl_blend_factor(state_bs->dst_factor_rgb), - _sg_gl_blend_factor(state_bs->src_factor_alpha), - _sg_gl_blend_factor(state_bs->dst_factor_alpha)); - _sg_stats_add(gl.num_render_state, 1); - } - if ((state_bs->op_rgb != cache_bs->op_rgb) || (state_bs->op_alpha != cache_bs->op_alpha)) { - cache_bs->op_rgb = state_bs->op_rgb; - cache_bs->op_alpha = state_bs->op_alpha; - glBlendEquationSeparate(_sg_gl_blend_op(state_bs->op_rgb), _sg_gl_blend_op(state_bs->op_alpha)); - _sg_stats_add(gl.num_render_state, 1); - } - - // standalone color target state - for (GLuint i = 0; i < (GLuint)pip->cmn.color_count; i++) { - if (pip->gl.color_write_mask[i] != _sg.gl.cache.color_write_mask[i]) { - const sg_color_mask cm = pip->gl.color_write_mask[i]; - _sg.gl.cache.color_write_mask[i] = cm; - #ifdef SOKOL_GLCORE - glColorMaski(i, - (cm & SG_COLORMASK_R) != 0, - (cm & SG_COLORMASK_G) != 0, - (cm & SG_COLORMASK_B) != 0, - (cm & SG_COLORMASK_A) != 0); - #else - if (0 == i) { - glColorMask((cm & SG_COLORMASK_R) != 0, - (cm & SG_COLORMASK_G) != 0, - (cm & SG_COLORMASK_B) != 0, - (cm & SG_COLORMASK_A) != 0); - } - #endif - _sg_stats_add(gl.num_render_state, 1); - } - } - - if (!_sg_fequal(pip->cmn.blend_color.r, _sg.gl.cache.blend_color.r, 0.0001f) || - !_sg_fequal(pip->cmn.blend_color.g, _sg.gl.cache.blend_color.g, 0.0001f) || - !_sg_fequal(pip->cmn.blend_color.b, _sg.gl.cache.blend_color.b, 0.0001f) || - !_sg_fequal(pip->cmn.blend_color.a, _sg.gl.cache.blend_color.a, 0.0001f)) - { - sg_color c = pip->cmn.blend_color; - _sg.gl.cache.blend_color = c; - glBlendColor(c.r, c.g, c.b, c.a); - _sg_stats_add(gl.num_render_state, 1); - } - } // pip->cmn.color_count > 0 - - if (pip->gl.cull_mode != _sg.gl.cache.cull_mode) { - _sg.gl.cache.cull_mode = pip->gl.cull_mode; - if (SG_CULLMODE_NONE == pip->gl.cull_mode) { - glDisable(GL_CULL_FACE); - _sg_stats_add(gl.num_render_state, 1); - } else { - glEnable(GL_CULL_FACE); - GLenum gl_mode = (SG_CULLMODE_FRONT == pip->gl.cull_mode) ? GL_FRONT : GL_BACK; - glCullFace(gl_mode); - _sg_stats_add(gl.num_render_state, 2); - } - } - if (pip->gl.face_winding != _sg.gl.cache.face_winding) { - _sg.gl.cache.face_winding = pip->gl.face_winding; - GLenum gl_winding = (SG_FACEWINDING_CW == pip->gl.face_winding) ? GL_CW : GL_CCW; - glFrontFace(gl_winding); - _sg_stats_add(gl.num_render_state, 1); - } - if (pip->gl.alpha_to_coverage_enabled != _sg.gl.cache.alpha_to_coverage_enabled) { - _sg.gl.cache.alpha_to_coverage_enabled = pip->gl.alpha_to_coverage_enabled; - if (pip->gl.alpha_to_coverage_enabled) { - glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); - } else { - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - } - _sg_stats_add(gl.num_render_state, 1); - } - #ifdef SOKOL_GLCORE - if (pip->gl.sample_count != _sg.gl.cache.sample_count) { - _sg.gl.cache.sample_count = pip->gl.sample_count; - if (pip->gl.sample_count > 1) { - glEnable(GL_MULTISAMPLE); - } else { - glDisable(GL_MULTISAMPLE); - } - _sg_stats_add(gl.num_render_state, 1); - } - #endif - - // bind shader program - if (pip->shader->gl.prog != _sg.gl.cache.prog) { - _sg.gl.cache.prog = pip->shader->gl.prog; - glUseProgram(pip->shader->gl.prog); - _sg_stats_add(gl.num_use_program, 1); - } - } - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE bool _sg_gl_apply_bindings(_sg_bindings_t* bnd) { - SOKOL_ASSERT(bnd); - SOKOL_ASSERT(bnd->pip); - _SG_GL_CHECK_ERROR(); - - // bind combined image-samplers - _SG_GL_CHECK_ERROR(); - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - const _sg_shader_stage_t* stage = &bnd->pip->shader->cmn.stage[stage_index]; - const _sg_gl_shader_stage_t* gl_stage = &bnd->pip->shader->gl.stage[stage_index]; - _sg_image_t** imgs = (stage_index == SG_SHADERSTAGE_VS) ? bnd->vs_imgs : bnd->fs_imgs; - _sg_sampler_t** smps = (stage_index == SG_SHADERSTAGE_VS) ? bnd->vs_smps : bnd->fs_smps; - const int num_imgs = (stage_index == SG_SHADERSTAGE_VS) ? bnd->num_vs_imgs : bnd->num_fs_imgs; - const int num_smps = (stage_index == SG_SHADERSTAGE_VS) ? bnd->num_vs_smps : bnd->num_fs_smps; - SOKOL_ASSERT(num_imgs == stage->num_images); _SOKOL_UNUSED(num_imgs); - SOKOL_ASSERT(num_smps == stage->num_samplers); _SOKOL_UNUSED(num_smps); - for (int img_smp_index = 0; img_smp_index < stage->num_image_samplers; img_smp_index++) { - const int gl_tex_slot = gl_stage->image_samplers[img_smp_index].gl_tex_slot; - if (gl_tex_slot != -1) { - const int img_index = stage->image_samplers[img_smp_index].image_slot; - const int smp_index = stage->image_samplers[img_smp_index].sampler_slot; - SOKOL_ASSERT(img_index < num_imgs); - SOKOL_ASSERT(smp_index < num_smps); - _sg_image_t* img = imgs[img_index]; - _sg_sampler_t* smp = smps[smp_index]; - const GLenum gl_tgt = img->gl.target; - const GLuint gl_tex = img->gl.tex[img->cmn.active_slot]; - const GLuint gl_smp = smp->gl.smp; - _sg_gl_cache_bind_texture_sampler(gl_tex_slot, gl_tgt, gl_tex, gl_smp); - } - } - } - _SG_GL_CHECK_ERROR(); - - // bind storage buffers - for (int slot = 0; slot < bnd->num_vs_sbufs; slot++) { - _sg_buffer_t* sb = bnd->vs_sbufs[slot]; - GLuint gl_sb = sb->gl.buf[sb->cmn.active_slot]; - _sg_gl_cache_bind_storage_buffer(SG_SHADERSTAGE_VS, slot, gl_sb); - } - for (int slot = 0; slot < bnd->num_fs_sbufs; slot++) { - _sg_buffer_t* sb = bnd->fs_sbufs[slot]; - GLuint gl_sb = sb->gl.buf[sb->cmn.active_slot]; - _sg_gl_cache_bind_storage_buffer(SG_SHADERSTAGE_FS, slot, gl_sb); - } - - // index buffer (can be 0) - const GLuint gl_ib = bnd->ib ? bnd->ib->gl.buf[bnd->ib->cmn.active_slot] : 0; - _sg_gl_cache_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, gl_ib); - _sg.gl.cache.cur_ib_offset = bnd->ib_offset; - - // vertex attributes - for (GLuint attr_index = 0; attr_index < (GLuint)_sg.limits.max_vertex_attrs; attr_index++) { - _sg_gl_attr_t* attr = &bnd->pip->gl.attrs[attr_index]; - _sg_gl_cache_attr_t* cache_attr = &_sg.gl.cache.attrs[attr_index]; - bool cache_attr_dirty = false; - int vb_offset = 0; - GLuint gl_vb = 0; - if (attr->vb_index >= 0) { - // attribute is enabled - SOKOL_ASSERT(attr->vb_index < bnd->num_vbs); - _sg_buffer_t* vb = bnd->vbs[attr->vb_index]; - SOKOL_ASSERT(vb); - gl_vb = vb->gl.buf[vb->cmn.active_slot]; - vb_offset = bnd->vb_offsets[attr->vb_index] + attr->offset; - if ((gl_vb != cache_attr->gl_vbuf) || - (attr->size != cache_attr->gl_attr.size) || - (attr->type != cache_attr->gl_attr.type) || - (attr->normalized != cache_attr->gl_attr.normalized) || - (attr->stride != cache_attr->gl_attr.stride) || - (vb_offset != cache_attr->gl_attr.offset) || - (cache_attr->gl_attr.divisor != attr->divisor)) - { - _sg_gl_cache_bind_buffer(GL_ARRAY_BUFFER, gl_vb); - glVertexAttribPointer(attr_index, attr->size, attr->type, attr->normalized, attr->stride, (const GLvoid*)(GLintptr)vb_offset); - _sg_stats_add(gl.num_vertex_attrib_pointer, 1); - glVertexAttribDivisor(attr_index, (GLuint)attr->divisor); - _sg_stats_add(gl.num_vertex_attrib_divisor, 1); - cache_attr_dirty = true; - } - if (cache_attr->gl_attr.vb_index == -1) { - glEnableVertexAttribArray(attr_index); - _sg_stats_add(gl.num_enable_vertex_attrib_array, 1); - cache_attr_dirty = true; - } - } else { - // attribute is disabled - if (cache_attr->gl_attr.vb_index != -1) { - glDisableVertexAttribArray(attr_index); - _sg_stats_add(gl.num_disable_vertex_attrib_array, 1); - cache_attr_dirty = true; - } - } - if (cache_attr_dirty) { - cache_attr->gl_attr = *attr; - cache_attr->gl_attr.offset = vb_offset; - cache_attr->gl_vbuf = gl_vb; - } - } - _SG_GL_CHECK_ERROR(); - return true; -} - -_SOKOL_PRIVATE void _sg_gl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { - SOKOL_ASSERT(_sg.gl.cache.cur_pipeline); - SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->slot.id == _sg.gl.cache.cur_pipeline_id.id); - SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->slot.id == _sg.gl.cache.cur_pipeline->cmn.shader_id.id); - SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks > ub_index); - SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size == data->size); - const _sg_gl_shader_stage_t* gl_stage = &_sg.gl.cache.cur_pipeline->shader->gl.stage[stage_index]; - const _sg_gl_uniform_block_t* gl_ub = &gl_stage->uniform_blocks[ub_index]; - for (int u_index = 0; u_index < gl_ub->num_uniforms; u_index++) { - const _sg_gl_uniform_t* u = &gl_ub->uniforms[u_index]; - SOKOL_ASSERT(u->type != SG_UNIFORMTYPE_INVALID); - if (u->gl_loc == -1) { - continue; - } - _sg_stats_add(gl.num_uniform, 1); - GLfloat* fptr = (GLfloat*) (((uint8_t*)data->ptr) + u->offset); - GLint* iptr = (GLint*) (((uint8_t*)data->ptr) + u->offset); - switch (u->type) { - case SG_UNIFORMTYPE_INVALID: - break; - case SG_UNIFORMTYPE_FLOAT: - glUniform1fv(u->gl_loc, u->count, fptr); - break; - case SG_UNIFORMTYPE_FLOAT2: - glUniform2fv(u->gl_loc, u->count, fptr); - break; - case SG_UNIFORMTYPE_FLOAT3: - glUniform3fv(u->gl_loc, u->count, fptr); - break; - case SG_UNIFORMTYPE_FLOAT4: - glUniform4fv(u->gl_loc, u->count, fptr); - break; - case SG_UNIFORMTYPE_INT: - glUniform1iv(u->gl_loc, u->count, iptr); - break; - case SG_UNIFORMTYPE_INT2: - glUniform2iv(u->gl_loc, u->count, iptr); - break; - case SG_UNIFORMTYPE_INT3: - glUniform3iv(u->gl_loc, u->count, iptr); - break; - case SG_UNIFORMTYPE_INT4: - glUniform4iv(u->gl_loc, u->count, iptr); - break; - case SG_UNIFORMTYPE_MAT4: - glUniformMatrix4fv(u->gl_loc, u->count, GL_FALSE, fptr); - break; - default: - SOKOL_UNREACHABLE; - break; - } - } -} - -_SOKOL_PRIVATE void _sg_gl_draw(int base_element, int num_elements, int num_instances) { - SOKOL_ASSERT(_sg.gl.cache.cur_pipeline); - const GLenum i_type = _sg.gl.cache.cur_index_type; - const GLenum p_type = _sg.gl.cache.cur_primitive_type; - const bool use_instanced_draw = (num_instances > 1) || (_sg.gl.cache.cur_pipeline->cmn.use_instanced_draw); - if (0 != i_type) { - // indexed rendering - const int i_size = (i_type == GL_UNSIGNED_SHORT) ? 2 : 4; - const int ib_offset = _sg.gl.cache.cur_ib_offset; - const GLvoid* indices = (const GLvoid*)(GLintptr)(base_element*i_size+ib_offset); - if (use_instanced_draw) { - glDrawElementsInstanced(p_type, num_elements, i_type, indices, num_instances); - } else { - glDrawElements(p_type, num_elements, i_type, indices); - } - } else { - // non-indexed rendering - if (use_instanced_draw) { - glDrawArraysInstanced(p_type, base_element, num_elements, num_instances); - } else { - glDrawArrays(p_type, base_element, num_elements); - } - } -} - -_SOKOL_PRIVATE void _sg_gl_commit(void) { - // "soft" clear bindings (only those that are actually bound) - _sg_gl_cache_clear_buffer_bindings(false); - _sg_gl_cache_clear_texture_sampler_bindings(false); -} - -_SOKOL_PRIVATE void _sg_gl_update_buffer(_sg_buffer_t* buf, const sg_range* data) { - SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); - // only one update per buffer per frame allowed - if (++buf->cmn.active_slot >= buf->cmn.num_slots) { - buf->cmn.active_slot = 0; - } - GLenum gl_tgt = _sg_gl_buffer_target(buf->cmn.type); - SOKOL_ASSERT(buf->cmn.active_slot < SG_NUM_INFLIGHT_FRAMES); - GLuint gl_buf = buf->gl.buf[buf->cmn.active_slot]; - SOKOL_ASSERT(gl_buf); - _SG_GL_CHECK_ERROR(); - _sg_gl_cache_store_buffer_binding(gl_tgt); - _sg_gl_cache_bind_buffer(gl_tgt, gl_buf); - glBufferSubData(gl_tgt, 0, (GLsizeiptr)data->size, data->ptr); - _sg_gl_cache_restore_buffer_binding(gl_tgt); - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE void _sg_gl_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { - SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); - if (new_frame) { - if (++buf->cmn.active_slot >= buf->cmn.num_slots) { - buf->cmn.active_slot = 0; - } - } - GLenum gl_tgt = _sg_gl_buffer_target(buf->cmn.type); - SOKOL_ASSERT(buf->cmn.active_slot < SG_NUM_INFLIGHT_FRAMES); - GLuint gl_buf = buf->gl.buf[buf->cmn.active_slot]; - SOKOL_ASSERT(gl_buf); - _SG_GL_CHECK_ERROR(); - _sg_gl_cache_store_buffer_binding(gl_tgt); - _sg_gl_cache_bind_buffer(gl_tgt, gl_buf); - glBufferSubData(gl_tgt, buf->cmn.append_pos, (GLsizeiptr)data->size, data->ptr); - _sg_gl_cache_restore_buffer_binding(gl_tgt); - _SG_GL_CHECK_ERROR(); -} - -_SOKOL_PRIVATE void _sg_gl_update_image(_sg_image_t* img, const sg_image_data* data) { - SOKOL_ASSERT(img && data); - // only one update per image per frame allowed - if (++img->cmn.active_slot >= img->cmn.num_slots) { - img->cmn.active_slot = 0; - } - SOKOL_ASSERT(img->cmn.active_slot < SG_NUM_INFLIGHT_FRAMES); - SOKOL_ASSERT(0 != img->gl.tex[img->cmn.active_slot]); - _sg_gl_cache_store_texture_sampler_binding(0); - _sg_gl_cache_bind_texture_sampler(0, img->gl.target, img->gl.tex[img->cmn.active_slot], 0); - const GLenum gl_img_format = _sg_gl_teximage_format(img->cmn.pixel_format); - const GLenum gl_img_type = _sg_gl_teximage_type(img->cmn.pixel_format); - const int num_faces = img->cmn.type == SG_IMAGETYPE_CUBE ? 6 : 1; - const int num_mips = img->cmn.num_mipmaps; - for (int face_index = 0; face_index < num_faces; face_index++) { - for (int mip_index = 0; mip_index < num_mips; mip_index++) { - GLenum gl_img_target = img->gl.target; - if (SG_IMAGETYPE_CUBE == img->cmn.type) { - gl_img_target = _sg_gl_cubeface_target(face_index); - } - const GLvoid* data_ptr = data->subimage[face_index][mip_index].ptr; - int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); - int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); - if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) { - glTexSubImage2D(gl_img_target, mip_index, - 0, 0, - mip_width, mip_height, - gl_img_format, gl_img_type, - data_ptr); - } else if ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type)) { - int mip_depth = img->cmn.num_slices; - if (SG_IMAGETYPE_3D == img->cmn.type) { - mip_depth = _sg_miplevel_dim(img->cmn.num_slices, mip_index); - } - glTexSubImage3D(gl_img_target, mip_index, - 0, 0, 0, - mip_width, mip_height, mip_depth, - gl_img_format, gl_img_type, - data_ptr); - - } - } - } - _sg_gl_cache_restore_texture_sampler_binding(0); -} - -// ██████ ██████ ██████ ██ ██ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ -// ██ ██ ██ ██ ██ ███ ███ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██ ██ █████ ██ ██ ██ ██ ██████ ███████ ██ █████ █████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██████ ██ ██ ██████ ██ ██ ██████ ██ ██ ███████ ██ ████ ██████ -// -// >>d3d11 backend -#elif defined(SOKOL_D3D11) - -#define _SG_D3D11_MAX_SHADERSTAGE_SRVS (32) -#define _SG_D3D11_SHADERSTAGE_IMAGE_SRV_OFFSET (0) -#define _SG_D3D11_SHADERSTAGE_BUFFER_SRV_OFFSET (16) - -#if defined(__cplusplus) -#define _sg_d3d11_AddRef(self) (self)->AddRef() -#else -#define _sg_d3d11_AddRef(self) (self)->lpVtbl->AddRef(self) -#endif - -#if defined(__cplusplus) -#define _sg_d3d11_Release(self) (self)->Release() -#else -#define _sg_d3d11_Release(self) (self)->lpVtbl->Release(self) -#endif - -// NOTE: This needs to be a macro since we can't use the polymorphism in C. It's called on many kinds of resources. -// NOTE: Based on microsoft docs, it's fine to call this with pData=NULL if DataSize is also zero. -#if defined(__cplusplus) -#define _sg_d3d11_SetPrivateData(self, guid, DataSize, pData) (self)->SetPrivateData(guid, DataSize, pData) -#else -#define _sg_d3d11_SetPrivateData(self, guid, DataSize, pData) (self)->lpVtbl->SetPrivateData(self, guid, DataSize, pData) -#endif - -#if defined(__cplusplus) -#define _sg_win32_refguid(guid) guid -#else -#define _sg_win32_refguid(guid) &guid -#endif - -static const GUID _sg_d3d11_WKPDID_D3DDebugObjectName = { 0x429b8c22,0x9188,0x4b0c, {0x87,0x42,0xac,0xb0,0xbf,0x85,0xc2,0x00} }; - -#if defined(SOKOL_DEBUG) -#define _sg_d3d11_setlabel(self, label) _sg_d3d11_SetPrivateData(self, _sg_win32_refguid(_sg_d3d11_WKPDID_D3DDebugObjectName), label ? (UINT)strlen(label) : 0, label) -#else -#define _sg_d3d11_setlabel(self, label) -#endif - - -//-- D3D11 C/C++ wrappers ------------------------------------------------------ -static inline HRESULT _sg_d3d11_CheckFormatSupport(ID3D11Device* self, DXGI_FORMAT Format, UINT* pFormatSupport) { - #if defined(__cplusplus) - return self->CheckFormatSupport(Format, pFormatSupport); - #else - return self->lpVtbl->CheckFormatSupport(self, Format, pFormatSupport); - #endif -} - -static inline void _sg_d3d11_OMSetRenderTargets(ID3D11DeviceContext* self, UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView *pDepthStencilView) { - #if defined(__cplusplus) - self->OMSetRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView); - #else - self->lpVtbl->OMSetRenderTargets(self, NumViews, ppRenderTargetViews, pDepthStencilView); - #endif -} - -static inline void _sg_d3d11_RSSetState(ID3D11DeviceContext* self, ID3D11RasterizerState* pRasterizerState) { - #if defined(__cplusplus) - self->RSSetState(pRasterizerState); - #else - self->lpVtbl->RSSetState(self, pRasterizerState); - #endif -} - -static inline void _sg_d3d11_OMSetDepthStencilState(ID3D11DeviceContext* self, ID3D11DepthStencilState* pDepthStencilState, UINT StencilRef) { - #if defined(__cplusplus) - self->OMSetDepthStencilState(pDepthStencilState, StencilRef); - #else - self->lpVtbl->OMSetDepthStencilState(self, pDepthStencilState, StencilRef); - #endif -} - -static inline void _sg_d3d11_OMSetBlendState(ID3D11DeviceContext* self, ID3D11BlendState* pBlendState, const FLOAT BlendFactor[4], UINT SampleMask) { - #if defined(__cplusplus) - self->OMSetBlendState(pBlendState, BlendFactor, SampleMask); - #else - self->lpVtbl->OMSetBlendState(self, pBlendState, BlendFactor, SampleMask); - #endif -} - -static inline void _sg_d3d11_IASetVertexBuffers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppVertexBuffers, const UINT* pStrides, const UINT* pOffsets) { - #if defined(__cplusplus) - self->IASetVertexBuffers(StartSlot, NumBuffers, ppVertexBuffers, pStrides, pOffsets); - #else - self->lpVtbl->IASetVertexBuffers(self, StartSlot, NumBuffers, ppVertexBuffers, pStrides, pOffsets); - #endif -} - -static inline void _sg_d3d11_IASetIndexBuffer(ID3D11DeviceContext* self, ID3D11Buffer* pIndexBuffer, DXGI_FORMAT Format, UINT Offset) { - #if defined(__cplusplus) - self->IASetIndexBuffer(pIndexBuffer, Format, Offset); - #else - self->lpVtbl->IASetIndexBuffer(self, pIndexBuffer, Format, Offset); - #endif -} - -static inline void _sg_d3d11_IASetInputLayout(ID3D11DeviceContext* self, ID3D11InputLayout* pInputLayout) { - #if defined(__cplusplus) - self->IASetInputLayout(pInputLayout); - #else - self->lpVtbl->IASetInputLayout(self, pInputLayout); - #endif -} - -static inline void _sg_d3d11_VSSetShader(ID3D11DeviceContext* self, ID3D11VertexShader* pVertexShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { - #if defined(__cplusplus) - self->VSSetShader(pVertexShader, ppClassInstances, NumClassInstances); - #else - self->lpVtbl->VSSetShader(self, pVertexShader, ppClassInstances, NumClassInstances); - #endif -} - -static inline void _sg_d3d11_PSSetShader(ID3D11DeviceContext* self, ID3D11PixelShader* pPixelShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { - #if defined(__cplusplus) - self->PSSetShader(pPixelShader, ppClassInstances, NumClassInstances); - #else - self->lpVtbl->PSSetShader(self, pPixelShader, ppClassInstances, NumClassInstances); - #endif -} - -static inline void _sg_d3d11_VSSetConstantBuffers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { - #if defined(__cplusplus) - self->VSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); - #else - self->lpVtbl->VSSetConstantBuffers(self, StartSlot, NumBuffers, ppConstantBuffers); - #endif -} - -static inline void _sg_d3d11_PSSetConstantBuffers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { - #if defined(__cplusplus) - self->PSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); - #else - self->lpVtbl->PSSetConstantBuffers(self, StartSlot, NumBuffers, ppConstantBuffers); - #endif -} - -static inline void _sg_d3d11_VSSetShaderResources(ID3D11DeviceContext* self, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { - #if defined(__cplusplus) - self->VSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); - #else - self->lpVtbl->VSSetShaderResources(self, StartSlot, NumViews, ppShaderResourceViews); - #endif -} - -static inline void _sg_d3d11_PSSetShaderResources(ID3D11DeviceContext* self, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { - #if defined(__cplusplus) - self->PSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); - #else - self->lpVtbl->PSSetShaderResources(self, StartSlot, NumViews, ppShaderResourceViews); - #endif -} - -static inline void _sg_d3d11_VSSetSamplers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { - #if defined(__cplusplus) - self->VSSetSamplers(StartSlot, NumSamplers, ppSamplers); - #else - self->lpVtbl->VSSetSamplers(self, StartSlot, NumSamplers, ppSamplers); - #endif -} - -static inline void _sg_d3d11_PSSetSamplers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { - #if defined(__cplusplus) - self->PSSetSamplers(StartSlot, NumSamplers, ppSamplers); - #else - self->lpVtbl->PSSetSamplers(self, StartSlot, NumSamplers, ppSamplers); - #endif -} - -static inline HRESULT _sg_d3d11_CreateBuffer(ID3D11Device* self, const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer) { - #if defined(__cplusplus) - return self->CreateBuffer(pDesc, pInitialData, ppBuffer); - #else - return self->lpVtbl->CreateBuffer(self, pDesc, pInitialData, ppBuffer); - #endif -} - -static inline HRESULT _sg_d3d11_CreateTexture2D(ID3D11Device* self, const D3D11_TEXTURE2D_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Texture2D** ppTexture2D) { - #if defined(__cplusplus) - return self->CreateTexture2D(pDesc, pInitialData, ppTexture2D); - #else - return self->lpVtbl->CreateTexture2D(self, pDesc, pInitialData, ppTexture2D); - #endif -} - -static inline HRESULT _sg_d3d11_CreateShaderResourceView(ID3D11Device* self, ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRView) { - #if defined(__cplusplus) - return self->CreateShaderResourceView(pResource, pDesc, ppSRView); - #else - return self->lpVtbl->CreateShaderResourceView(self, pResource, pDesc, ppSRView); - #endif -} - -static inline void _sg_d3d11_GetResource(ID3D11View* self, ID3D11Resource** ppResource) { - #if defined(__cplusplus) - self->GetResource(ppResource); - #else - self->lpVtbl->GetResource(self, ppResource); - #endif -} - -static inline HRESULT _sg_d3d11_CreateTexture3D(ID3D11Device* self, const D3D11_TEXTURE3D_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Texture3D** ppTexture3D) { - #if defined(__cplusplus) - return self->CreateTexture3D(pDesc, pInitialData, ppTexture3D); - #else - return self->lpVtbl->CreateTexture3D(self, pDesc, pInitialData, ppTexture3D); - #endif -} - -static inline HRESULT _sg_d3d11_CreateSamplerState(ID3D11Device* self, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState) { - #if defined(__cplusplus) - return self->CreateSamplerState(pSamplerDesc, ppSamplerState); - #else - return self->lpVtbl->CreateSamplerState(self, pSamplerDesc, ppSamplerState); - #endif -} - -static inline LPVOID _sg_d3d11_GetBufferPointer(ID3D10Blob* self) { - #if defined(__cplusplus) - return self->GetBufferPointer(); - #else - return self->lpVtbl->GetBufferPointer(self); - #endif -} - -static inline SIZE_T _sg_d3d11_GetBufferSize(ID3D10Blob* self) { - #if defined(__cplusplus) - return self->GetBufferSize(); - #else - return self->lpVtbl->GetBufferSize(self); - #endif -} - -static inline HRESULT _sg_d3d11_CreateVertexShader(ID3D11Device* self, const void* pShaderBytecode, SIZE_T BytecodeLength, ID3D11ClassLinkage* pClassLinkage, ID3D11VertexShader** ppVertexShader) { - #if defined(__cplusplus) - return self->CreateVertexShader(pShaderBytecode, BytecodeLength, pClassLinkage, ppVertexShader); - #else - return self->lpVtbl->CreateVertexShader(self, pShaderBytecode, BytecodeLength, pClassLinkage, ppVertexShader); - #endif -} - -static inline HRESULT _sg_d3d11_CreatePixelShader(ID3D11Device* self, const void* pShaderBytecode, SIZE_T BytecodeLength, ID3D11ClassLinkage* pClassLinkage, ID3D11PixelShader** ppPixelShader) { - #if defined(__cplusplus) - return self->CreatePixelShader(pShaderBytecode, BytecodeLength, pClassLinkage, ppPixelShader); - #else - return self->lpVtbl->CreatePixelShader(self, pShaderBytecode, BytecodeLength, pClassLinkage, ppPixelShader); - #endif -} - -static inline HRESULT _sg_d3d11_CreateInputLayout(ID3D11Device* self, const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements, const void* pShaderBytecodeWithInputSignature, SIZE_T BytecodeLength, ID3D11InputLayout **ppInputLayout) { - #if defined(__cplusplus) - return self->CreateInputLayout(pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, ppInputLayout); - #else - return self->lpVtbl->CreateInputLayout(self, pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, ppInputLayout); - #endif -} - -static inline HRESULT _sg_d3d11_CreateRasterizerState(ID3D11Device* self, const D3D11_RASTERIZER_DESC* pRasterizerDesc, ID3D11RasterizerState** ppRasterizerState) { - #if defined(__cplusplus) - return self->CreateRasterizerState(pRasterizerDesc, ppRasterizerState); - #else - return self->lpVtbl->CreateRasterizerState(self, pRasterizerDesc, ppRasterizerState); - #endif -} - -static inline HRESULT _sg_d3d11_CreateDepthStencilState(ID3D11Device* self, const D3D11_DEPTH_STENCIL_DESC* pDepthStencilDesc, ID3D11DepthStencilState** ppDepthStencilState) { - #if defined(__cplusplus) - return self->CreateDepthStencilState(pDepthStencilDesc, ppDepthStencilState); - #else - return self->lpVtbl->CreateDepthStencilState(self, pDepthStencilDesc, ppDepthStencilState); - #endif -} - -static inline HRESULT _sg_d3d11_CreateBlendState(ID3D11Device* self, const D3D11_BLEND_DESC* pBlendStateDesc, ID3D11BlendState** ppBlendState) { - #if defined(__cplusplus) - return self->CreateBlendState(pBlendStateDesc, ppBlendState); - #else - return self->lpVtbl->CreateBlendState(self, pBlendStateDesc, ppBlendState); - #endif -} - -static inline HRESULT _sg_d3d11_CreateRenderTargetView(ID3D11Device* self, ID3D11Resource *pResource, const D3D11_RENDER_TARGET_VIEW_DESC* pDesc, ID3D11RenderTargetView** ppRTView) { - #if defined(__cplusplus) - return self->CreateRenderTargetView(pResource, pDesc, ppRTView); - #else - return self->lpVtbl->CreateRenderTargetView(self, pResource, pDesc, ppRTView); - #endif -} - -static inline HRESULT _sg_d3d11_CreateDepthStencilView(ID3D11Device* self, ID3D11Resource* pResource, const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc, ID3D11DepthStencilView** ppDepthStencilView) { - #if defined(__cplusplus) - return self->CreateDepthStencilView(pResource, pDesc, ppDepthStencilView); - #else - return self->lpVtbl->CreateDepthStencilView(self, pResource, pDesc, ppDepthStencilView); - #endif -} - -static inline void _sg_d3d11_RSSetViewports(ID3D11DeviceContext* self, UINT NumViewports, const D3D11_VIEWPORT* pViewports) { - #if defined(__cplusplus) - self->RSSetViewports(NumViewports, pViewports); - #else - self->lpVtbl->RSSetViewports(self, NumViewports, pViewports); - #endif -} - -static inline void _sg_d3d11_RSSetScissorRects(ID3D11DeviceContext* self, UINT NumRects, const D3D11_RECT* pRects) { - #if defined(__cplusplus) - self->RSSetScissorRects(NumRects, pRects); - #else - self->lpVtbl->RSSetScissorRects(self, NumRects, pRects); - #endif -} - -static inline void _sg_d3d11_ClearRenderTargetView(ID3D11DeviceContext* self, ID3D11RenderTargetView* pRenderTargetView, const FLOAT ColorRGBA[4]) { - #if defined(__cplusplus) - self->ClearRenderTargetView(pRenderTargetView, ColorRGBA); - #else - self->lpVtbl->ClearRenderTargetView(self, pRenderTargetView, ColorRGBA); - #endif -} - -static inline void _sg_d3d11_ClearDepthStencilView(ID3D11DeviceContext* self, ID3D11DepthStencilView* pDepthStencilView, UINT ClearFlags, FLOAT Depth, UINT8 Stencil) { - #if defined(__cplusplus) - self->ClearDepthStencilView(pDepthStencilView, ClearFlags, Depth, Stencil); - #else - self->lpVtbl->ClearDepthStencilView(self, pDepthStencilView, ClearFlags, Depth, Stencil); - #endif -} - -static inline void _sg_d3d11_ResolveSubresource(ID3D11DeviceContext* self, ID3D11Resource* pDstResource, UINT DstSubresource, ID3D11Resource* pSrcResource, UINT SrcSubresource, DXGI_FORMAT Format) { - #if defined(__cplusplus) - self->ResolveSubresource(pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); - #else - self->lpVtbl->ResolveSubresource(self, pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); - #endif -} - -static inline void _sg_d3d11_IASetPrimitiveTopology(ID3D11DeviceContext* self, D3D11_PRIMITIVE_TOPOLOGY Topology) { - #if defined(__cplusplus) - self->IASetPrimitiveTopology(Topology); - #else - self->lpVtbl->IASetPrimitiveTopology(self, Topology); - #endif -} - -static inline void _sg_d3d11_UpdateSubresource(ID3D11DeviceContext* self, ID3D11Resource* pDstResource, UINT DstSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch) { - #if defined(__cplusplus) - self->UpdateSubresource(pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch); - #else - self->lpVtbl->UpdateSubresource(self, pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch); - #endif -} - -static inline void _sg_d3d11_DrawIndexed(ID3D11DeviceContext* self, UINT IndexCount, UINT StartIndexLocation, INT BaseVertexLocation) { - #if defined(__cplusplus) - self->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation); - #else - self->lpVtbl->DrawIndexed(self, IndexCount, StartIndexLocation, BaseVertexLocation); - #endif -} - -static inline void _sg_d3d11_DrawIndexedInstanced(ID3D11DeviceContext* self, UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation) { - #if defined(__cplusplus) - self->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); - #else - self->lpVtbl->DrawIndexedInstanced(self, IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); - #endif -} - -static inline void _sg_d3d11_Draw(ID3D11DeviceContext* self, UINT VertexCount, UINT StartVertexLocation) { - #if defined(__cplusplus) - self->Draw(VertexCount, StartVertexLocation); - #else - self->lpVtbl->Draw(self, VertexCount, StartVertexLocation); - #endif -} - -static inline void _sg_d3d11_DrawInstanced(ID3D11DeviceContext* self, UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation) { - #if defined(__cplusplus) - self->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); - #else - self->lpVtbl->DrawInstanced(self, VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); - #endif -} - -static inline HRESULT _sg_d3d11_Map(ID3D11DeviceContext* self, ID3D11Resource* pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE* pMappedResource) { - #if defined(__cplusplus) - return self->Map(pResource, Subresource, MapType, MapFlags, pMappedResource); - #else - return self->lpVtbl->Map(self, pResource, Subresource, MapType, MapFlags, pMappedResource); - #endif -} - -static inline void _sg_d3d11_Unmap(ID3D11DeviceContext* self, ID3D11Resource* pResource, UINT Subresource) { - #if defined(__cplusplus) - self->Unmap(pResource, Subresource); - #else - self->lpVtbl->Unmap(self, pResource, Subresource); - #endif -} - -static inline void _sg_d3d11_ClearState(ID3D11DeviceContext* self) { - #if defined(__cplusplus) - self->ClearState(); - #else - self->lpVtbl->ClearState(self); - #endif -} - -//-- enum translation functions ------------------------------------------------ -_SOKOL_PRIVATE D3D11_USAGE _sg_d3d11_usage(sg_usage usg) { - switch (usg) { - case SG_USAGE_IMMUTABLE: - return D3D11_USAGE_IMMUTABLE; - case SG_USAGE_DYNAMIC: - case SG_USAGE_STREAM: - return D3D11_USAGE_DYNAMIC; - default: - SOKOL_UNREACHABLE; - return (D3D11_USAGE) 0; - } -} - -_SOKOL_PRIVATE UINT _sg_d3d11_buffer_bind_flags(sg_buffer_type t) { - switch (t) { - case SG_BUFFERTYPE_VERTEXBUFFER: - return D3D11_BIND_VERTEX_BUFFER; - case SG_BUFFERTYPE_INDEXBUFFER: - return D3D11_BIND_INDEX_BUFFER; - case SG_BUFFERTYPE_STORAGEBUFFER: - // FIXME: for compute shaders we'd want UNORDERED_ACCESS? - return D3D11_BIND_SHADER_RESOURCE; - default: - SOKOL_UNREACHABLE; - return 0; - } -} - -_SOKOL_PRIVATE UINT _sg_d3d11_buffer_misc_flags(sg_buffer_type t) { - switch (t) { - case SG_BUFFERTYPE_VERTEXBUFFER: - case SG_BUFFERTYPE_INDEXBUFFER: - return 0; - case SG_BUFFERTYPE_STORAGEBUFFER: - return D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; - default: - SOKOL_UNREACHABLE; - return 0; - } -} - -_SOKOL_PRIVATE UINT _sg_d3d11_cpu_access_flags(sg_usage usg) { - switch (usg) { - case SG_USAGE_IMMUTABLE: - return 0; - case SG_USAGE_DYNAMIC: - case SG_USAGE_STREAM: - return D3D11_CPU_ACCESS_WRITE; - default: - SOKOL_UNREACHABLE; - return 0; - } -} - -_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_texture_pixel_format(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_R8: return DXGI_FORMAT_R8_UNORM; - case SG_PIXELFORMAT_R8SN: return DXGI_FORMAT_R8_SNORM; - case SG_PIXELFORMAT_R8UI: return DXGI_FORMAT_R8_UINT; - case SG_PIXELFORMAT_R8SI: return DXGI_FORMAT_R8_SINT; - case SG_PIXELFORMAT_R16: return DXGI_FORMAT_R16_UNORM; - case SG_PIXELFORMAT_R16SN: return DXGI_FORMAT_R16_SNORM; - case SG_PIXELFORMAT_R16UI: return DXGI_FORMAT_R16_UINT; - case SG_PIXELFORMAT_R16SI: return DXGI_FORMAT_R16_SINT; - case SG_PIXELFORMAT_R16F: return DXGI_FORMAT_R16_FLOAT; - case SG_PIXELFORMAT_RG8: return DXGI_FORMAT_R8G8_UNORM; - case SG_PIXELFORMAT_RG8SN: return DXGI_FORMAT_R8G8_SNORM; - case SG_PIXELFORMAT_RG8UI: return DXGI_FORMAT_R8G8_UINT; - case SG_PIXELFORMAT_RG8SI: return DXGI_FORMAT_R8G8_SINT; - case SG_PIXELFORMAT_R32UI: return DXGI_FORMAT_R32_UINT; - case SG_PIXELFORMAT_R32SI: return DXGI_FORMAT_R32_SINT; - case SG_PIXELFORMAT_R32F: return DXGI_FORMAT_R32_FLOAT; - case SG_PIXELFORMAT_RG16: return DXGI_FORMAT_R16G16_UNORM; - case SG_PIXELFORMAT_RG16SN: return DXGI_FORMAT_R16G16_SNORM; - case SG_PIXELFORMAT_RG16UI: return DXGI_FORMAT_R16G16_UINT; - case SG_PIXELFORMAT_RG16SI: return DXGI_FORMAT_R16G16_SINT; - case SG_PIXELFORMAT_RG16F: return DXGI_FORMAT_R16G16_FLOAT; - case SG_PIXELFORMAT_RGBA8: return DXGI_FORMAT_R8G8B8A8_UNORM; - case SG_PIXELFORMAT_SRGB8A8: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - case SG_PIXELFORMAT_RGBA8SN: return DXGI_FORMAT_R8G8B8A8_SNORM; - case SG_PIXELFORMAT_RGBA8UI: return DXGI_FORMAT_R8G8B8A8_UINT; - case SG_PIXELFORMAT_RGBA8SI: return DXGI_FORMAT_R8G8B8A8_SINT; - case SG_PIXELFORMAT_BGRA8: return DXGI_FORMAT_B8G8R8A8_UNORM; - case SG_PIXELFORMAT_RGB10A2: return DXGI_FORMAT_R10G10B10A2_UNORM; - case SG_PIXELFORMAT_RG11B10F: return DXGI_FORMAT_R11G11B10_FLOAT; - case SG_PIXELFORMAT_RGB9E5: return DXGI_FORMAT_R9G9B9E5_SHAREDEXP; - case SG_PIXELFORMAT_RG32UI: return DXGI_FORMAT_R32G32_UINT; - case SG_PIXELFORMAT_RG32SI: return DXGI_FORMAT_R32G32_SINT; - case SG_PIXELFORMAT_RG32F: return DXGI_FORMAT_R32G32_FLOAT; - case SG_PIXELFORMAT_RGBA16: return DXGI_FORMAT_R16G16B16A16_UNORM; - case SG_PIXELFORMAT_RGBA16SN: return DXGI_FORMAT_R16G16B16A16_SNORM; - case SG_PIXELFORMAT_RGBA16UI: return DXGI_FORMAT_R16G16B16A16_UINT; - case SG_PIXELFORMAT_RGBA16SI: return DXGI_FORMAT_R16G16B16A16_SINT; - case SG_PIXELFORMAT_RGBA16F: return DXGI_FORMAT_R16G16B16A16_FLOAT; - case SG_PIXELFORMAT_RGBA32UI: return DXGI_FORMAT_R32G32B32A32_UINT; - case SG_PIXELFORMAT_RGBA32SI: return DXGI_FORMAT_R32G32B32A32_SINT; - case SG_PIXELFORMAT_RGBA32F: return DXGI_FORMAT_R32G32B32A32_FLOAT; - case SG_PIXELFORMAT_DEPTH: return DXGI_FORMAT_R32_TYPELESS; - case SG_PIXELFORMAT_DEPTH_STENCIL: return DXGI_FORMAT_R24G8_TYPELESS; - case SG_PIXELFORMAT_BC1_RGBA: return DXGI_FORMAT_BC1_UNORM; - case SG_PIXELFORMAT_BC2_RGBA: return DXGI_FORMAT_BC2_UNORM; - case SG_PIXELFORMAT_BC3_RGBA: return DXGI_FORMAT_BC3_UNORM; - case SG_PIXELFORMAT_BC3_SRGBA: return DXGI_FORMAT_BC3_UNORM_SRGB; - case SG_PIXELFORMAT_BC4_R: return DXGI_FORMAT_BC4_UNORM; - case SG_PIXELFORMAT_BC4_RSN: return DXGI_FORMAT_BC4_SNORM; - case SG_PIXELFORMAT_BC5_RG: return DXGI_FORMAT_BC5_UNORM; - case SG_PIXELFORMAT_BC5_RGSN: return DXGI_FORMAT_BC5_SNORM; - case SG_PIXELFORMAT_BC6H_RGBF: return DXGI_FORMAT_BC6H_SF16; - case SG_PIXELFORMAT_BC6H_RGBUF: return DXGI_FORMAT_BC6H_UF16; - case SG_PIXELFORMAT_BC7_RGBA: return DXGI_FORMAT_BC7_UNORM; - case SG_PIXELFORMAT_BC7_SRGBA: return DXGI_FORMAT_BC7_UNORM_SRGB; - default: return DXGI_FORMAT_UNKNOWN; - }; -} - -_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_srv_pixel_format(sg_pixel_format fmt) { - if (fmt == SG_PIXELFORMAT_DEPTH) { - return DXGI_FORMAT_R32_FLOAT; - } else if (fmt == SG_PIXELFORMAT_DEPTH_STENCIL) { - return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; - } else { - return _sg_d3d11_texture_pixel_format(fmt); - } -} - -_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_dsv_pixel_format(sg_pixel_format fmt) { - if (fmt == SG_PIXELFORMAT_DEPTH) { - return DXGI_FORMAT_D32_FLOAT; - } else if (fmt == SG_PIXELFORMAT_DEPTH_STENCIL) { - return DXGI_FORMAT_D24_UNORM_S8_UINT; - } else { - return _sg_d3d11_texture_pixel_format(fmt); - } -} - -_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_rtv_pixel_format(sg_pixel_format fmt) { - if (fmt == SG_PIXELFORMAT_DEPTH) { - return DXGI_FORMAT_R32_FLOAT; - } else if (fmt == SG_PIXELFORMAT_DEPTH_STENCIL) { - return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; - } else { - return _sg_d3d11_texture_pixel_format(fmt); - } -} - -_SOKOL_PRIVATE D3D11_PRIMITIVE_TOPOLOGY _sg_d3d11_primitive_topology(sg_primitive_type prim_type) { - switch (prim_type) { - case SG_PRIMITIVETYPE_POINTS: return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; - case SG_PRIMITIVETYPE_LINES: return D3D11_PRIMITIVE_TOPOLOGY_LINELIST; - case SG_PRIMITIVETYPE_LINE_STRIP: return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP; - case SG_PRIMITIVETYPE_TRIANGLES: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; - default: SOKOL_UNREACHABLE; return (D3D11_PRIMITIVE_TOPOLOGY) 0; - } -} - -_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_index_format(sg_index_type index_type) { - switch (index_type) { - case SG_INDEXTYPE_NONE: return DXGI_FORMAT_UNKNOWN; - case SG_INDEXTYPE_UINT16: return DXGI_FORMAT_R16_UINT; - case SG_INDEXTYPE_UINT32: return DXGI_FORMAT_R32_UINT; - default: SOKOL_UNREACHABLE; return (DXGI_FORMAT) 0; - } -} - -_SOKOL_PRIVATE D3D11_FILTER _sg_d3d11_filter(sg_filter min_f, sg_filter mag_f, sg_filter mipmap_f, bool comparison, uint32_t max_anisotropy) { - uint32_t d3d11_filter = 0; - if (max_anisotropy > 1) { - // D3D11_FILTER_ANISOTROPIC = 0x55, - d3d11_filter |= 0x55; - } else { - // D3D11_FILTER_MIN_MAG_MIP_POINT = 0, - // D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR = 0x1, - // D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x4, - // D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR = 0x5, - // D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT = 0x10, - // D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11, - // D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14, - // D3D11_FILTER_MIN_MAG_MIP_LINEAR = 0x15, - if (mipmap_f == SG_FILTER_LINEAR) { - d3d11_filter |= 0x01; - } - if (mag_f == SG_FILTER_LINEAR) { - d3d11_filter |= 0x04; - } - if (min_f == SG_FILTER_LINEAR) { - d3d11_filter |= 0x10; - } - } - // D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT = 0x80, - // D3D11_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 0x81, - // D3D11_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x84, - // D3D11_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR = 0x85, - // D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT = 0x90, - // D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x91, - // D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 0x94, - // D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR = 0x95, - // D3D11_FILTER_COMPARISON_ANISOTROPIC = 0xd5, - if (comparison) { - d3d11_filter |= 0x80; - } - return (D3D11_FILTER)d3d11_filter; -} - -_SOKOL_PRIVATE D3D11_TEXTURE_ADDRESS_MODE _sg_d3d11_address_mode(sg_wrap m) { - switch (m) { - case SG_WRAP_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP; - case SG_WRAP_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP; - case SG_WRAP_CLAMP_TO_BORDER: return D3D11_TEXTURE_ADDRESS_BORDER; - case SG_WRAP_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR; - default: SOKOL_UNREACHABLE; return (D3D11_TEXTURE_ADDRESS_MODE) 0; - } -} - -_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_vertex_format(sg_vertex_format fmt) { - switch (fmt) { - case SG_VERTEXFORMAT_FLOAT: return DXGI_FORMAT_R32_FLOAT; - case SG_VERTEXFORMAT_FLOAT2: return DXGI_FORMAT_R32G32_FLOAT; - case SG_VERTEXFORMAT_FLOAT3: return DXGI_FORMAT_R32G32B32_FLOAT; - case SG_VERTEXFORMAT_FLOAT4: return DXGI_FORMAT_R32G32B32A32_FLOAT; - case SG_VERTEXFORMAT_BYTE4: return DXGI_FORMAT_R8G8B8A8_SINT; - case SG_VERTEXFORMAT_BYTE4N: return DXGI_FORMAT_R8G8B8A8_SNORM; - case SG_VERTEXFORMAT_UBYTE4: return DXGI_FORMAT_R8G8B8A8_UINT; - case SG_VERTEXFORMAT_UBYTE4N: return DXGI_FORMAT_R8G8B8A8_UNORM; - case SG_VERTEXFORMAT_SHORT2: return DXGI_FORMAT_R16G16_SINT; - case SG_VERTEXFORMAT_SHORT2N: return DXGI_FORMAT_R16G16_SNORM; - case SG_VERTEXFORMAT_USHORT2N: return DXGI_FORMAT_R16G16_UNORM; - case SG_VERTEXFORMAT_SHORT4: return DXGI_FORMAT_R16G16B16A16_SINT; - case SG_VERTEXFORMAT_SHORT4N: return DXGI_FORMAT_R16G16B16A16_SNORM; - case SG_VERTEXFORMAT_USHORT4N: return DXGI_FORMAT_R16G16B16A16_UNORM; - case SG_VERTEXFORMAT_UINT10_N2: return DXGI_FORMAT_R10G10B10A2_UNORM; - case SG_VERTEXFORMAT_HALF2: return DXGI_FORMAT_R16G16_FLOAT; - case SG_VERTEXFORMAT_HALF4: return DXGI_FORMAT_R16G16B16A16_FLOAT; - default: SOKOL_UNREACHABLE; return (DXGI_FORMAT) 0; - } -} - -_SOKOL_PRIVATE D3D11_INPUT_CLASSIFICATION _sg_d3d11_input_classification(sg_vertex_step step) { - switch (step) { - case SG_VERTEXSTEP_PER_VERTEX: return D3D11_INPUT_PER_VERTEX_DATA; - case SG_VERTEXSTEP_PER_INSTANCE: return D3D11_INPUT_PER_INSTANCE_DATA; - default: SOKOL_UNREACHABLE; return (D3D11_INPUT_CLASSIFICATION) 0; - } -} - -_SOKOL_PRIVATE D3D11_CULL_MODE _sg_d3d11_cull_mode(sg_cull_mode m) { - switch (m) { - case SG_CULLMODE_NONE: return D3D11_CULL_NONE; - case SG_CULLMODE_FRONT: return D3D11_CULL_FRONT; - case SG_CULLMODE_BACK: return D3D11_CULL_BACK; - default: SOKOL_UNREACHABLE; return (D3D11_CULL_MODE) 0; - } -} - -_SOKOL_PRIVATE D3D11_COMPARISON_FUNC _sg_d3d11_compare_func(sg_compare_func f) { - switch (f) { - case SG_COMPAREFUNC_NEVER: return D3D11_COMPARISON_NEVER; - case SG_COMPAREFUNC_LESS: return D3D11_COMPARISON_LESS; - case SG_COMPAREFUNC_EQUAL: return D3D11_COMPARISON_EQUAL; - case SG_COMPAREFUNC_LESS_EQUAL: return D3D11_COMPARISON_LESS_EQUAL; - case SG_COMPAREFUNC_GREATER: return D3D11_COMPARISON_GREATER; - case SG_COMPAREFUNC_NOT_EQUAL: return D3D11_COMPARISON_NOT_EQUAL; - case SG_COMPAREFUNC_GREATER_EQUAL: return D3D11_COMPARISON_GREATER_EQUAL; - case SG_COMPAREFUNC_ALWAYS: return D3D11_COMPARISON_ALWAYS; - default: SOKOL_UNREACHABLE; return (D3D11_COMPARISON_FUNC) 0; - } -} - -_SOKOL_PRIVATE D3D11_STENCIL_OP _sg_d3d11_stencil_op(sg_stencil_op op) { - switch (op) { - case SG_STENCILOP_KEEP: return D3D11_STENCIL_OP_KEEP; - case SG_STENCILOP_ZERO: return D3D11_STENCIL_OP_ZERO; - case SG_STENCILOP_REPLACE: return D3D11_STENCIL_OP_REPLACE; - case SG_STENCILOP_INCR_CLAMP: return D3D11_STENCIL_OP_INCR_SAT; - case SG_STENCILOP_DECR_CLAMP: return D3D11_STENCIL_OP_DECR_SAT; - case SG_STENCILOP_INVERT: return D3D11_STENCIL_OP_INVERT; - case SG_STENCILOP_INCR_WRAP: return D3D11_STENCIL_OP_INCR; - case SG_STENCILOP_DECR_WRAP: return D3D11_STENCIL_OP_DECR; - default: SOKOL_UNREACHABLE; return (D3D11_STENCIL_OP) 0; - } -} - -_SOKOL_PRIVATE D3D11_BLEND _sg_d3d11_blend_factor(sg_blend_factor f) { - switch (f) { - case SG_BLENDFACTOR_ZERO: return D3D11_BLEND_ZERO; - case SG_BLENDFACTOR_ONE: return D3D11_BLEND_ONE; - case SG_BLENDFACTOR_SRC_COLOR: return D3D11_BLEND_SRC_COLOR; - case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return D3D11_BLEND_INV_SRC_COLOR; - case SG_BLENDFACTOR_SRC_ALPHA: return D3D11_BLEND_SRC_ALPHA; - case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return D3D11_BLEND_INV_SRC_ALPHA; - case SG_BLENDFACTOR_DST_COLOR: return D3D11_BLEND_DEST_COLOR; - case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return D3D11_BLEND_INV_DEST_COLOR; - case SG_BLENDFACTOR_DST_ALPHA: return D3D11_BLEND_DEST_ALPHA; - case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return D3D11_BLEND_INV_DEST_ALPHA; - case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return D3D11_BLEND_SRC_ALPHA_SAT; - case SG_BLENDFACTOR_BLEND_COLOR: return D3D11_BLEND_BLEND_FACTOR; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return D3D11_BLEND_INV_BLEND_FACTOR; - case SG_BLENDFACTOR_BLEND_ALPHA: return D3D11_BLEND_BLEND_FACTOR; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return D3D11_BLEND_INV_BLEND_FACTOR; - default: SOKOL_UNREACHABLE; return (D3D11_BLEND) 0; - } -} - -_SOKOL_PRIVATE D3D11_BLEND_OP _sg_d3d11_blend_op(sg_blend_op op) { - switch (op) { - case SG_BLENDOP_ADD: return D3D11_BLEND_OP_ADD; - case SG_BLENDOP_SUBTRACT: return D3D11_BLEND_OP_SUBTRACT; - case SG_BLENDOP_REVERSE_SUBTRACT: return D3D11_BLEND_OP_REV_SUBTRACT; - default: SOKOL_UNREACHABLE; return (D3D11_BLEND_OP) 0; - } -} - -_SOKOL_PRIVATE UINT8 _sg_d3d11_color_write_mask(sg_color_mask m) { - UINT8 res = 0; - if (m & SG_COLORMASK_R) { - res |= D3D11_COLOR_WRITE_ENABLE_RED; - } - if (m & SG_COLORMASK_G) { - res |= D3D11_COLOR_WRITE_ENABLE_GREEN; - } - if (m & SG_COLORMASK_B) { - res |= D3D11_COLOR_WRITE_ENABLE_BLUE; - } - if (m & SG_COLORMASK_A) { - res |= D3D11_COLOR_WRITE_ENABLE_ALPHA; - } - return res; -} - -_SOKOL_PRIVATE UINT _sg_d3d11_dxgi_fmt_caps(DXGI_FORMAT dxgi_fmt) { - UINT dxgi_fmt_caps = 0; - if (dxgi_fmt != DXGI_FORMAT_UNKNOWN) { - HRESULT hr = _sg_d3d11_CheckFormatSupport(_sg.d3d11.dev, dxgi_fmt, &dxgi_fmt_caps); - SOKOL_ASSERT(SUCCEEDED(hr) || (E_FAIL == hr)); - if (!SUCCEEDED(hr)) { - dxgi_fmt_caps = 0; - } - } - return dxgi_fmt_caps; -} - -// see: https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-limits#resource-limits-for-feature-level-11-hardware -_SOKOL_PRIVATE void _sg_d3d11_init_caps(void) { - _sg.backend = SG_BACKEND_D3D11; - - _sg.features.origin_top_left = true; - _sg.features.image_clamp_to_border = true; - _sg.features.mrt_independent_blend_state = true; - _sg.features.mrt_independent_write_mask = true; - _sg.features.storage_buffer = true; - - _sg.limits.max_image_size_2d = 16 * 1024; - _sg.limits.max_image_size_cube = 16 * 1024; - _sg.limits.max_image_size_3d = 2 * 1024; - _sg.limits.max_image_size_array = 16 * 1024; - _sg.limits.max_image_array_layers = 2 * 1024; - _sg.limits.max_vertex_attrs = SG_MAX_VERTEX_ATTRIBUTES; - - // see: https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_format_support - for (int fmt = (SG_PIXELFORMAT_NONE+1); fmt < _SG_PIXELFORMAT_NUM; fmt++) { - const UINT srv_dxgi_fmt_caps = _sg_d3d11_dxgi_fmt_caps(_sg_d3d11_srv_pixel_format((sg_pixel_format)fmt)); - const UINT rtv_dxgi_fmt_caps = _sg_d3d11_dxgi_fmt_caps(_sg_d3d11_rtv_pixel_format((sg_pixel_format)fmt)); - const UINT dsv_dxgi_fmt_caps = _sg_d3d11_dxgi_fmt_caps(_sg_d3d11_dsv_pixel_format((sg_pixel_format)fmt)); - _sg_pixelformat_info_t* info = &_sg.formats[fmt]; - const bool render = 0 != (rtv_dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_RENDER_TARGET); - const bool depth = 0 != (dsv_dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL); - info->sample = 0 != (srv_dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_TEXTURE2D); - info->filter = 0 != (srv_dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE); - info->render = render || depth; - info->blend = 0 != (rtv_dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_BLENDABLE); - info->msaa = 0 != (rtv_dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET); - info->depth = depth; - } -} - -_SOKOL_PRIVATE void _sg_d3d11_setup_backend(const sg_desc* desc) { - // assume _sg.d3d11 already is zero-initialized - SOKOL_ASSERT(desc); - SOKOL_ASSERT(desc->environment.d3d11.device); - SOKOL_ASSERT(desc->environment.d3d11.device_context); - _sg.d3d11.valid = true; - _sg.d3d11.dev = (ID3D11Device*) desc->environment.d3d11.device; - _sg.d3d11.ctx = (ID3D11DeviceContext*) desc->environment.d3d11.device_context; - _sg_d3d11_init_caps(); -} - -_SOKOL_PRIVATE void _sg_d3d11_discard_backend(void) { - SOKOL_ASSERT(_sg.d3d11.valid); - _sg.d3d11.valid = false; -} - -_SOKOL_PRIVATE void _sg_d3d11_clear_state(void) { - // clear all the device context state, so that resource refs don't keep stuck in the d3d device context - _sg_d3d11_ClearState(_sg.d3d11.ctx); -} - -_SOKOL_PRIVATE void _sg_d3d11_reset_state_cache(void) { - // just clear the d3d11 device context state - _sg_d3d11_clear_state(); -} - -_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { - SOKOL_ASSERT(buf && desc); - SOKOL_ASSERT(!buf->d3d11.buf); - const bool injected = (0 != desc->d3d11_buffer); - if (injected) { - buf->d3d11.buf = (ID3D11Buffer*) desc->d3d11_buffer; - _sg_d3d11_AddRef(buf->d3d11.buf); - // FIXME: for storage buffers also need to inject resource view - } else { - D3D11_BUFFER_DESC d3d11_buf_desc; - _sg_clear(&d3d11_buf_desc, sizeof(d3d11_buf_desc)); - d3d11_buf_desc.ByteWidth = (UINT)buf->cmn.size; - d3d11_buf_desc.Usage = _sg_d3d11_usage(buf->cmn.usage); - d3d11_buf_desc.BindFlags = _sg_d3d11_buffer_bind_flags(buf->cmn.type); - d3d11_buf_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(buf->cmn.usage); - d3d11_buf_desc.MiscFlags = _sg_d3d11_buffer_misc_flags(buf->cmn.type); - D3D11_SUBRESOURCE_DATA* init_data_ptr = 0; - D3D11_SUBRESOURCE_DATA init_data; - _sg_clear(&init_data, sizeof(init_data)); - if (buf->cmn.usage == SG_USAGE_IMMUTABLE) { - SOKOL_ASSERT(desc->data.ptr); - init_data.pSysMem = desc->data.ptr; - init_data_ptr = &init_data; - } - HRESULT hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &d3d11_buf_desc, init_data_ptr, &buf->d3d11.buf); - if (!(SUCCEEDED(hr) && buf->d3d11.buf)) { - _SG_ERROR(D3D11_CREATE_BUFFER_FAILED); - return SG_RESOURCESTATE_FAILED; - } - - // for storage buffers need to create a view object - if (buf->cmn.type == SG_BUFFERTYPE_STORAGEBUFFER) { - // FIXME: currently only shader-resource-view, in future also UAV - // storage buffer size must be multiple of 4 - SOKOL_ASSERT(_sg_multiple_u64(buf->cmn.size, 4)); - D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; - _sg_clear(&d3d11_srv_desc, sizeof(d3d11_srv_desc)); - d3d11_srv_desc.Format = DXGI_FORMAT_R32_TYPELESS; - d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; - d3d11_srv_desc.BufferEx.FirstElement = 0; - d3d11_srv_desc.BufferEx.NumElements = buf->cmn.size / 4; - d3d11_srv_desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW; - hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)buf->d3d11.buf, &d3d11_srv_desc, &buf->d3d11.srv); - if (!(SUCCEEDED(hr) && buf->d3d11.srv)) { - _SG_ERROR(D3D11_CREATE_BUFFER_SRV_FAILED); - return SG_RESOURCESTATE_FAILED; - } - } - _sg_d3d11_setlabel(buf->d3d11.buf, desc->label); - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_d3d11_discard_buffer(_sg_buffer_t* buf) { - SOKOL_ASSERT(buf); - if (buf->d3d11.buf) { - _sg_d3d11_Release(buf->d3d11.buf); - } - if (buf->d3d11.srv) { - _sg_d3d11_Release(buf->d3d11.srv); - } -} - -_SOKOL_PRIVATE void _sg_d3d11_fill_subres_data(const _sg_image_t* img, const sg_image_data* data) { - const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; - const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices:1; - int subres_index = 0; - for (int face_index = 0; face_index < num_faces; face_index++) { - for (int slice_index = 0; slice_index < num_slices; slice_index++) { - for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, subres_index++) { - SOKOL_ASSERT(subres_index < (SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS)); - D3D11_SUBRESOURCE_DATA* subres_data = &_sg.d3d11.subres_data[subres_index]; - const int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); - const int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); - const sg_range* subimg_data = &(data->subimage[face_index][mip_index]); - const size_t slice_size = subimg_data->size / (size_t)num_slices; - const size_t slice_offset = slice_size * (size_t)slice_index; - const uint8_t* ptr = (const uint8_t*) subimg_data->ptr; - subres_data->pSysMem = ptr + slice_offset; - subres_data->SysMemPitch = (UINT)_sg_row_pitch(img->cmn.pixel_format, mip_width, 1); - if (img->cmn.type == SG_IMAGETYPE_3D) { - // FIXME? const int mip_depth = _sg_miplevel_dim(img->depth, mip_index); - subres_data->SysMemSlicePitch = (UINT)_sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1); - } else { - subres_data->SysMemSlicePitch = 0; - } - } - } - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const sg_image_desc* desc) { - SOKOL_ASSERT(img && desc); - SOKOL_ASSERT((0 == img->d3d11.tex2d) && (0 == img->d3d11.tex3d) && (0 == img->d3d11.res) && (0 == img->d3d11.srv)); - HRESULT hr; - - const bool injected = (0 != desc->d3d11_texture); - const bool msaa = (img->cmn.sample_count > 1); - img->d3d11.format = _sg_d3d11_texture_pixel_format(img->cmn.pixel_format); - if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { - _SG_ERROR(D3D11_CREATE_2D_TEXTURE_UNSUPPORTED_PIXEL_FORMAT); - return SG_RESOURCESTATE_FAILED; - } - - // prepare initial content pointers - D3D11_SUBRESOURCE_DATA* init_data = 0; - if (!injected && (img->cmn.usage == SG_USAGE_IMMUTABLE) && !img->cmn.render_target) { - _sg_d3d11_fill_subres_data(img, &desc->data); - init_data = _sg.d3d11.subres_data; - } - if (img->cmn.type != SG_IMAGETYPE_3D) { - // 2D-, cube- or array-texture - // first check for injected texture and/or resource view - if (injected) { - img->d3d11.tex2d = (ID3D11Texture2D*) desc->d3d11_texture; - _sg_d3d11_AddRef(img->d3d11.tex2d); - img->d3d11.srv = (ID3D11ShaderResourceView*) desc->d3d11_shader_resource_view; - if (img->d3d11.srv) { - _sg_d3d11_AddRef(img->d3d11.srv); - } - } else { - // if not injected, create 2D texture - D3D11_TEXTURE2D_DESC d3d11_tex_desc; - _sg_clear(&d3d11_tex_desc, sizeof(d3d11_tex_desc)); - d3d11_tex_desc.Width = (UINT)img->cmn.width; - d3d11_tex_desc.Height = (UINT)img->cmn.height; - d3d11_tex_desc.MipLevels = (UINT)img->cmn.num_mipmaps; - switch (img->cmn.type) { - case SG_IMAGETYPE_ARRAY: d3d11_tex_desc.ArraySize = (UINT)img->cmn.num_slices; break; - case SG_IMAGETYPE_CUBE: d3d11_tex_desc.ArraySize = 6; break; - default: d3d11_tex_desc.ArraySize = 1; break; - } - d3d11_tex_desc.Format = img->d3d11.format; - if (img->cmn.render_target) { - d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; - if (_sg_is_depth_or_depth_stencil_format(img->cmn.pixel_format)) { - d3d11_tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - } else { - d3d11_tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET; - } - if (!msaa) { - d3d11_tex_desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; - } - d3d11_tex_desc.CPUAccessFlags = 0; - } else { - d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage); - d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage); - } - d3d11_tex_desc.SampleDesc.Count = (UINT)img->cmn.sample_count; - d3d11_tex_desc.SampleDesc.Quality = (UINT) (msaa ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0); - d3d11_tex_desc.MiscFlags = (img->cmn.type == SG_IMAGETYPE_CUBE) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0; - - hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_tex_desc, init_data, &img->d3d11.tex2d); - if (!(SUCCEEDED(hr) && img->d3d11.tex2d)) { - _SG_ERROR(D3D11_CREATE_2D_TEXTURE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(img->d3d11.tex2d, desc->label); - - // create shader-resource-view for 2D texture - // FIXME: currently we don't support setting MSAA texture as shader resource - if (!msaa) { - D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; - _sg_clear(&d3d11_srv_desc, sizeof(d3d11_srv_desc)); - d3d11_srv_desc.Format = _sg_d3d11_srv_pixel_format(img->cmn.pixel_format); - switch (img->cmn.type) { - case SG_IMAGETYPE_2D: - d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - d3d11_srv_desc.Texture2D.MipLevels = (UINT)img->cmn.num_mipmaps; - break; - case SG_IMAGETYPE_CUBE: - d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - d3d11_srv_desc.TextureCube.MipLevels = (UINT)img->cmn.num_mipmaps; - break; - case SG_IMAGETYPE_ARRAY: - d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - d3d11_srv_desc.Texture2DArray.MipLevels = (UINT)img->cmn.num_mipmaps; - d3d11_srv_desc.Texture2DArray.ArraySize = (UINT)img->cmn.num_slices; - break; - default: - SOKOL_UNREACHABLE; break; - } - hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex2d, &d3d11_srv_desc, &img->d3d11.srv); - if (!(SUCCEEDED(hr) && img->d3d11.srv)) { - _SG_ERROR(D3D11_CREATE_2D_SRV_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(img->d3d11.srv, desc->label); - } - } - SOKOL_ASSERT(img->d3d11.tex2d); - img->d3d11.res = (ID3D11Resource*)img->d3d11.tex2d; - _sg_d3d11_AddRef(img->d3d11.res); - } else { - // 3D texture - same procedure, first check if injected, than create non-injected - if (injected) { - img->d3d11.tex3d = (ID3D11Texture3D*) desc->d3d11_texture; - _sg_d3d11_AddRef(img->d3d11.tex3d); - img->d3d11.srv = (ID3D11ShaderResourceView*) desc->d3d11_shader_resource_view; - if (img->d3d11.srv) { - _sg_d3d11_AddRef(img->d3d11.srv); - } - } else { - // not injected, create 3d texture - D3D11_TEXTURE3D_DESC d3d11_tex_desc; - _sg_clear(&d3d11_tex_desc, sizeof(d3d11_tex_desc)); - d3d11_tex_desc.Width = (UINT)img->cmn.width; - d3d11_tex_desc.Height = (UINT)img->cmn.height; - d3d11_tex_desc.Depth = (UINT)img->cmn.num_slices; - d3d11_tex_desc.MipLevels = (UINT)img->cmn.num_mipmaps; - d3d11_tex_desc.Format = img->d3d11.format; - if (img->cmn.render_target) { - d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; - d3d11_tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET; - d3d11_tex_desc.CPUAccessFlags = 0; - } else { - d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage); - d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage); - } - if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { - _SG_ERROR(D3D11_CREATE_3D_TEXTURE_UNSUPPORTED_PIXEL_FORMAT); - return SG_RESOURCESTATE_FAILED; - } - hr = _sg_d3d11_CreateTexture3D(_sg.d3d11.dev, &d3d11_tex_desc, init_data, &img->d3d11.tex3d); - if (!(SUCCEEDED(hr) && img->d3d11.tex3d)) { - _SG_ERROR(D3D11_CREATE_3D_TEXTURE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(img->d3d11.tex3d, desc->label); - - // create shader-resource-view for 3D texture - if (!msaa) { - D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; - _sg_clear(&d3d11_srv_desc, sizeof(d3d11_srv_desc)); - d3d11_srv_desc.Format = _sg_d3d11_srv_pixel_format(img->cmn.pixel_format); - d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; - d3d11_srv_desc.Texture3D.MipLevels = (UINT)img->cmn.num_mipmaps; - hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex3d, &d3d11_srv_desc, &img->d3d11.srv); - if (!(SUCCEEDED(hr) && img->d3d11.srv)) { - _SG_ERROR(D3D11_CREATE_3D_SRV_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(img->d3d11.srv, desc->label); - } - } - SOKOL_ASSERT(img->d3d11.tex3d); - img->d3d11.res = (ID3D11Resource*)img->d3d11.tex3d; - _sg_d3d11_AddRef(img->d3d11.res); - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_d3d11_discard_image(_sg_image_t* img) { - SOKOL_ASSERT(img); - if (img->d3d11.tex2d) { - _sg_d3d11_Release(img->d3d11.tex2d); - } - if (img->d3d11.tex3d) { - _sg_d3d11_Release(img->d3d11.tex3d); - } - if (img->d3d11.res) { - _sg_d3d11_Release(img->d3d11.res); - } - if (img->d3d11.srv) { - _sg_d3d11_Release(img->d3d11.srv); - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_sampler(_sg_sampler_t* smp, const sg_sampler_desc* desc) { - SOKOL_ASSERT(smp && desc); - SOKOL_ASSERT(0 == smp->d3d11.smp); - const bool injected = (0 != desc->d3d11_sampler); - if (injected) { - smp->d3d11.smp = (ID3D11SamplerState*)desc->d3d11_sampler; - _sg_d3d11_AddRef(smp->d3d11.smp); - } else { - D3D11_SAMPLER_DESC d3d11_smp_desc; - _sg_clear(&d3d11_smp_desc, sizeof(d3d11_smp_desc)); - d3d11_smp_desc.Filter = _sg_d3d11_filter(desc->min_filter, desc->mag_filter, desc->mipmap_filter, desc->compare != SG_COMPAREFUNC_NEVER, desc->max_anisotropy); - d3d11_smp_desc.AddressU = _sg_d3d11_address_mode(desc->wrap_u); - d3d11_smp_desc.AddressV = _sg_d3d11_address_mode(desc->wrap_v); - d3d11_smp_desc.AddressW = _sg_d3d11_address_mode(desc->wrap_w); - d3d11_smp_desc.MipLODBias = 0.0f; // FIXME? - switch (desc->border_color) { - case SG_BORDERCOLOR_TRANSPARENT_BLACK: - // all 0.0f - break; - case SG_BORDERCOLOR_OPAQUE_WHITE: - for (int i = 0; i < 4; i++) { - d3d11_smp_desc.BorderColor[i] = 1.0f; - } - break; - default: - // opaque black - d3d11_smp_desc.BorderColor[3] = 1.0f; - break; - } - d3d11_smp_desc.MaxAnisotropy = desc->max_anisotropy; - d3d11_smp_desc.ComparisonFunc = _sg_d3d11_compare_func(desc->compare); - d3d11_smp_desc.MinLOD = desc->min_lod; - d3d11_smp_desc.MaxLOD = desc->max_lod; - HRESULT hr = _sg_d3d11_CreateSamplerState(_sg.d3d11.dev, &d3d11_smp_desc, &smp->d3d11.smp); - if (!(SUCCEEDED(hr) && smp->d3d11.smp)) { - _SG_ERROR(D3D11_CREATE_SAMPLER_STATE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(smp->d3d11.smp, desc->label); - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_d3d11_discard_sampler(_sg_sampler_t* smp) { - SOKOL_ASSERT(smp); - if (smp->d3d11.smp) { - _sg_d3d11_Release(smp->d3d11.smp); - } -} - -_SOKOL_PRIVATE bool _sg_d3d11_load_d3dcompiler_dll(void) { - if ((0 == _sg.d3d11.d3dcompiler_dll) && !_sg.d3d11.d3dcompiler_dll_load_failed) { - _sg.d3d11.d3dcompiler_dll = LoadLibraryA("d3dcompiler_47.dll"); - if (0 == _sg.d3d11.d3dcompiler_dll) { - // don't attempt to load missing DLL in the future - _SG_ERROR(D3D11_LOAD_D3DCOMPILER_47_DLL_FAILED); - _sg.d3d11.d3dcompiler_dll_load_failed = true; - return false; - } - // look up function pointers - _sg.d3d11.D3DCompile_func = (pD3DCompile)(void*) GetProcAddress(_sg.d3d11.d3dcompiler_dll, "D3DCompile"); - SOKOL_ASSERT(_sg.d3d11.D3DCompile_func); - } - return 0 != _sg.d3d11.d3dcompiler_dll; -} - -_SOKOL_PRIVATE ID3DBlob* _sg_d3d11_compile_shader(const sg_shader_stage_desc* stage_desc) { - if (!_sg_d3d11_load_d3dcompiler_dll()) { - return NULL; - } - SOKOL_ASSERT(stage_desc->d3d11_target); - UINT flags1 = D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR; - if (_sg.desc.d3d11_shader_debugging) { - flags1 |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; - } else { - flags1 |= D3DCOMPILE_OPTIMIZATION_LEVEL3; - } - ID3DBlob* output = NULL; - ID3DBlob* errors_or_warnings = NULL; - HRESULT hr = _sg.d3d11.D3DCompile_func( - stage_desc->source, // pSrcData - strlen(stage_desc->source), // SrcDataSize - NULL, // pSourceName - NULL, // pDefines - NULL, // pInclude - stage_desc->entry ? stage_desc->entry : "main", // pEntryPoint - stage_desc->d3d11_target, // pTarget - flags1, // Flags1 - 0, // Flags2 - &output, // ppCode - &errors_or_warnings); // ppErrorMsgs - if (FAILED(hr)) { - _SG_ERROR(D3D11_SHADER_COMPILATION_FAILED); - } - if (errors_or_warnings) { - _SG_WARN(D3D11_SHADER_COMPILATION_OUTPUT); - _SG_LOGMSG(D3D11_SHADER_COMPILATION_OUTPUT, (LPCSTR)_sg_d3d11_GetBufferPointer(errors_or_warnings)); - _sg_d3d11_Release(errors_or_warnings); errors_or_warnings = NULL; - } - if (FAILED(hr)) { - // just in case, usually output is NULL here - if (output) { - _sg_d3d11_Release(output); - output = NULL; - } - } - return output; -} - -_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { - SOKOL_ASSERT(shd && desc); - SOKOL_ASSERT(!shd->d3d11.vs && !shd->d3d11.fs && !shd->d3d11.vs_blob); - HRESULT hr; - - // copy vertex attribute semantic names and indices - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - _sg_strcpy(&shd->d3d11.attrs[i].sem_name, desc->attrs[i].sem_name); - shd->d3d11.attrs[i].sem_index = desc->attrs[i].sem_index; - } - - // shader stage uniform blocks and image slots - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - _sg_shader_stage_t* cmn_stage = &shd->cmn.stage[stage_index]; - _sg_d3d11_shader_stage_t* d3d11_stage = &shd->d3d11.stage[stage_index]; - for (int ub_index = 0; ub_index < cmn_stage->num_uniform_blocks; ub_index++) { - const _sg_shader_uniform_block_t* ub = &cmn_stage->uniform_blocks[ub_index]; - - // create a D3D constant buffer for each uniform block - SOKOL_ASSERT(0 == d3d11_stage->cbufs[ub_index]); - D3D11_BUFFER_DESC cb_desc; - _sg_clear(&cb_desc, sizeof(cb_desc)); - cb_desc.ByteWidth = (UINT)_sg_roundup((int)ub->size, 16); - cb_desc.Usage = D3D11_USAGE_DEFAULT; - cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &cb_desc, NULL, &d3d11_stage->cbufs[ub_index]); - if (!(SUCCEEDED(hr) && d3d11_stage->cbufs[ub_index])) { - _SG_ERROR(D3D11_CREATE_CONSTANT_BUFFER_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(d3d11_stage->cbufs[ub_index], desc->label); - } - } - - const void* vs_ptr = 0, *fs_ptr = 0; - SIZE_T vs_length = 0, fs_length = 0; - ID3DBlob* vs_blob = 0, *fs_blob = 0; - if (desc->vs.bytecode.ptr && desc->fs.bytecode.ptr) { - // create from shader byte code - vs_ptr = desc->vs.bytecode.ptr; - fs_ptr = desc->fs.bytecode.ptr; - vs_length = desc->vs.bytecode.size; - fs_length = desc->fs.bytecode.size; - } else { - // compile from shader source code - vs_blob = _sg_d3d11_compile_shader(&desc->vs); - fs_blob = _sg_d3d11_compile_shader(&desc->fs); - if (vs_blob && fs_blob) { - vs_ptr = _sg_d3d11_GetBufferPointer(vs_blob); - vs_length = _sg_d3d11_GetBufferSize(vs_blob); - fs_ptr = _sg_d3d11_GetBufferPointer(fs_blob); - fs_length = _sg_d3d11_GetBufferSize(fs_blob); - } - } - sg_resource_state result = SG_RESOURCESTATE_FAILED; - if (vs_ptr && fs_ptr && (vs_length > 0) && (fs_length > 0)) { - // create the D3D vertex- and pixel-shader objects - hr = _sg_d3d11_CreateVertexShader(_sg.d3d11.dev, vs_ptr, vs_length, NULL, &shd->d3d11.vs); - bool vs_succeeded = SUCCEEDED(hr) && shd->d3d11.vs; - hr = _sg_d3d11_CreatePixelShader(_sg.d3d11.dev, fs_ptr, fs_length, NULL, &shd->d3d11.fs); - bool fs_succeeded = SUCCEEDED(hr) && shd->d3d11.fs; - - // need to store the vertex shader byte code, this is needed later in sg_create_pipeline - if (vs_succeeded && fs_succeeded) { - shd->d3d11.vs_blob_length = vs_length; - shd->d3d11.vs_blob = _sg_malloc((size_t)vs_length); - SOKOL_ASSERT(shd->d3d11.vs_blob); - memcpy(shd->d3d11.vs_blob, vs_ptr, vs_length); - result = SG_RESOURCESTATE_VALID; - _sg_d3d11_setlabel(shd->d3d11.vs, desc->label); - _sg_d3d11_setlabel(shd->d3d11.fs, desc->label); - } - } - if (vs_blob) { - _sg_d3d11_Release(vs_blob); vs_blob = 0; - } - if (fs_blob) { - _sg_d3d11_Release(fs_blob); fs_blob = 0; - } - return result; -} - -_SOKOL_PRIVATE void _sg_d3d11_discard_shader(_sg_shader_t* shd) { - SOKOL_ASSERT(shd); - if (shd->d3d11.vs) { - _sg_d3d11_Release(shd->d3d11.vs); - } - if (shd->d3d11.fs) { - _sg_d3d11_Release(shd->d3d11.fs); - } - if (shd->d3d11.vs_blob) { - _sg_free(shd->d3d11.vs_blob); - } - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - _sg_shader_stage_t* cmn_stage = &shd->cmn.stage[stage_index]; - _sg_d3d11_shader_stage_t* d3d11_stage = &shd->d3d11.stage[stage_index]; - for (int ub_index = 0; ub_index < cmn_stage->num_uniform_blocks; ub_index++) { - if (d3d11_stage->cbufs[ub_index]) { - _sg_d3d11_Release(d3d11_stage->cbufs[ub_index]); - } - } - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { - SOKOL_ASSERT(pip && shd && desc); - SOKOL_ASSERT(desc->shader.id == shd->slot.id); - SOKOL_ASSERT(shd->slot.state == SG_RESOURCESTATE_VALID); - SOKOL_ASSERT(shd->d3d11.vs_blob && shd->d3d11.vs_blob_length > 0); - SOKOL_ASSERT(!pip->d3d11.il && !pip->d3d11.rs && !pip->d3d11.dss && !pip->d3d11.bs); - - pip->shader = shd; - pip->d3d11.index_format = _sg_d3d11_index_format(pip->cmn.index_type); - pip->d3d11.topology = _sg_d3d11_primitive_topology(desc->primitive_type); - pip->d3d11.stencil_ref = desc->stencil.ref; - - // create input layout object - HRESULT hr; - D3D11_INPUT_ELEMENT_DESC d3d11_comps[SG_MAX_VERTEX_ATTRIBUTES]; - _sg_clear(d3d11_comps, sizeof(d3d11_comps)); - int attr_index = 0; - for (; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { - const sg_vertex_attr_state* a_state = &desc->layout.attrs[attr_index]; - if (a_state->format == SG_VERTEXFORMAT_INVALID) { - break; - } - SOKOL_ASSERT(a_state->buffer_index < SG_MAX_VERTEX_BUFFERS); - const sg_vertex_buffer_layout_state* l_state = &desc->layout.buffers[a_state->buffer_index]; - const sg_vertex_step step_func = l_state->step_func; - const int step_rate = l_state->step_rate; - D3D11_INPUT_ELEMENT_DESC* d3d11_comp = &d3d11_comps[attr_index]; - d3d11_comp->SemanticName = _sg_strptr(&shd->d3d11.attrs[attr_index].sem_name); - d3d11_comp->SemanticIndex = (UINT)shd->d3d11.attrs[attr_index].sem_index; - d3d11_comp->Format = _sg_d3d11_vertex_format(a_state->format); - d3d11_comp->InputSlot = (UINT)a_state->buffer_index; - d3d11_comp->AlignedByteOffset = (UINT)a_state->offset; - d3d11_comp->InputSlotClass = _sg_d3d11_input_classification(step_func); - if (SG_VERTEXSTEP_PER_INSTANCE == step_func) { - d3d11_comp->InstanceDataStepRate = (UINT)step_rate; - pip->cmn.use_instanced_draw = true; - } - pip->cmn.vertex_buffer_layout_active[a_state->buffer_index] = true; - } - for (int layout_index = 0; layout_index < SG_MAX_VERTEX_BUFFERS; layout_index++) { - if (pip->cmn.vertex_buffer_layout_active[layout_index]) { - const sg_vertex_buffer_layout_state* l_state = &desc->layout.buffers[layout_index]; - SOKOL_ASSERT(l_state->stride > 0); - pip->d3d11.vb_strides[layout_index] = (UINT)l_state->stride; - } else { - pip->d3d11.vb_strides[layout_index] = 0; - } - } - if (attr_index > 0) { - hr = _sg_d3d11_CreateInputLayout(_sg.d3d11.dev, - d3d11_comps, // pInputElementDesc - (UINT)attr_index, // NumElements - shd->d3d11.vs_blob, // pShaderByteCodeWithInputSignature - shd->d3d11.vs_blob_length, // BytecodeLength - &pip->d3d11.il); - if (!(SUCCEEDED(hr) && pip->d3d11.il)) { - _SG_ERROR(D3D11_CREATE_INPUT_LAYOUT_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(pip->d3d11.il, desc->label); - } - - // create rasterizer state - D3D11_RASTERIZER_DESC rs_desc; - _sg_clear(&rs_desc, sizeof(rs_desc)); - rs_desc.FillMode = D3D11_FILL_SOLID; - rs_desc.CullMode = _sg_d3d11_cull_mode(desc->cull_mode); - rs_desc.FrontCounterClockwise = desc->face_winding == SG_FACEWINDING_CCW; - rs_desc.DepthBias = (INT) pip->cmn.depth.bias; - rs_desc.DepthBiasClamp = pip->cmn.depth.bias_clamp; - rs_desc.SlopeScaledDepthBias = pip->cmn.depth.bias_slope_scale; - rs_desc.DepthClipEnable = TRUE; - rs_desc.ScissorEnable = TRUE; - rs_desc.MultisampleEnable = desc->sample_count > 1; - rs_desc.AntialiasedLineEnable = FALSE; - hr = _sg_d3d11_CreateRasterizerState(_sg.d3d11.dev, &rs_desc, &pip->d3d11.rs); - if (!(SUCCEEDED(hr) && pip->d3d11.rs)) { - _SG_ERROR(D3D11_CREATE_RASTERIZER_STATE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(pip->d3d11.rs, desc->label); - - // create depth-stencil state - D3D11_DEPTH_STENCIL_DESC dss_desc; - _sg_clear(&dss_desc, sizeof(dss_desc)); - dss_desc.DepthEnable = TRUE; - dss_desc.DepthWriteMask = desc->depth.write_enabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - dss_desc.DepthFunc = _sg_d3d11_compare_func(desc->depth.compare); - dss_desc.StencilEnable = desc->stencil.enabled; - dss_desc.StencilReadMask = desc->stencil.read_mask; - dss_desc.StencilWriteMask = desc->stencil.write_mask; - const sg_stencil_face_state* sf = &desc->stencil.front; - dss_desc.FrontFace.StencilFailOp = _sg_d3d11_stencil_op(sf->fail_op); - dss_desc.FrontFace.StencilDepthFailOp = _sg_d3d11_stencil_op(sf->depth_fail_op); - dss_desc.FrontFace.StencilPassOp = _sg_d3d11_stencil_op(sf->pass_op); - dss_desc.FrontFace.StencilFunc = _sg_d3d11_compare_func(sf->compare); - const sg_stencil_face_state* sb = &desc->stencil.back; - dss_desc.BackFace.StencilFailOp = _sg_d3d11_stencil_op(sb->fail_op); - dss_desc.BackFace.StencilDepthFailOp = _sg_d3d11_stencil_op(sb->depth_fail_op); - dss_desc.BackFace.StencilPassOp = _sg_d3d11_stencil_op(sb->pass_op); - dss_desc.BackFace.StencilFunc = _sg_d3d11_compare_func(sb->compare); - hr = _sg_d3d11_CreateDepthStencilState(_sg.d3d11.dev, &dss_desc, &pip->d3d11.dss); - if (!(SUCCEEDED(hr) && pip->d3d11.dss)) { - _SG_ERROR(D3D11_CREATE_DEPTH_STENCIL_STATE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(pip->d3d11.dss, desc->label); - - // create blend state - D3D11_BLEND_DESC bs_desc; - _sg_clear(&bs_desc, sizeof(bs_desc)); - bs_desc.AlphaToCoverageEnable = desc->alpha_to_coverage_enabled; - bs_desc.IndependentBlendEnable = TRUE; - { - int i = 0; - for (i = 0; i < desc->color_count; i++) { - const sg_blend_state* src = &desc->colors[i].blend; - D3D11_RENDER_TARGET_BLEND_DESC* dst = &bs_desc.RenderTarget[i]; - dst->BlendEnable = src->enabled; - dst->SrcBlend = _sg_d3d11_blend_factor(src->src_factor_rgb); - dst->DestBlend = _sg_d3d11_blend_factor(src->dst_factor_rgb); - dst->BlendOp = _sg_d3d11_blend_op(src->op_rgb); - dst->SrcBlendAlpha = _sg_d3d11_blend_factor(src->src_factor_alpha); - dst->DestBlendAlpha = _sg_d3d11_blend_factor(src->dst_factor_alpha); - dst->BlendOpAlpha = _sg_d3d11_blend_op(src->op_alpha); - dst->RenderTargetWriteMask = _sg_d3d11_color_write_mask(desc->colors[i].write_mask); - } - for (; i < 8; i++) { - D3D11_RENDER_TARGET_BLEND_DESC* dst = &bs_desc.RenderTarget[i]; - dst->BlendEnable = FALSE; - dst->SrcBlend = dst->SrcBlendAlpha = D3D11_BLEND_ONE; - dst->DestBlend = dst->DestBlendAlpha = D3D11_BLEND_ZERO; - dst->BlendOp = dst->BlendOpAlpha = D3D11_BLEND_OP_ADD; - dst->RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - } - } - hr = _sg_d3d11_CreateBlendState(_sg.d3d11.dev, &bs_desc, &pip->d3d11.bs); - if (!(SUCCEEDED(hr) && pip->d3d11.bs)) { - _SG_ERROR(D3D11_CREATE_BLEND_STATE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(pip->d3d11.bs, desc->label); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_d3d11_discard_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - if (pip == _sg.d3d11.cur_pipeline) { - _sg.d3d11.cur_pipeline = 0; - _sg.d3d11.cur_pipeline_id.id = SG_INVALID_ID; - } - if (pip->d3d11.il) { - _sg_d3d11_Release(pip->d3d11.il); - } - if (pip->d3d11.rs) { - _sg_d3d11_Release(pip->d3d11.rs); - } - if (pip->d3d11.dss) { - _sg_d3d11_Release(pip->d3d11.dss); - } - if (pip->d3d11.bs) { - _sg_d3d11_Release(pip->d3d11.bs); - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_attachments_desc* desc) { - SOKOL_ASSERT(atts && desc); - SOKOL_ASSERT(color_images && resolve_images); - SOKOL_ASSERT(_sg.d3d11.dev); - - // copy image pointers - for (int i = 0; i < atts->cmn.num_colors; i++) { - const sg_attachment_desc* color_desc = &desc->colors[i]; - _SOKOL_UNUSED(color_desc); - SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == atts->d3d11.colors[i].image); - SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); - atts->d3d11.colors[i].image = color_images[i]; - - const sg_attachment_desc* resolve_desc = &desc->resolves[i]; - if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == atts->d3d11.resolves[i].image); - SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); - SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); - atts->d3d11.resolves[i].image = resolve_images[i]; - } - } - SOKOL_ASSERT(0 == atts->d3d11.depth_stencil.image); - const sg_attachment_desc* ds_desc = &desc->depth_stencil; - if (ds_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(ds_img && (ds_img->slot.id == ds_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_img->cmn.pixel_format)); - atts->d3d11.depth_stencil.image = ds_img; - } - - // create render-target views - for (int i = 0; i < atts->cmn.num_colors; i++) { - const _sg_attachment_common_t* cmn_color_att = &atts->cmn.colors[i]; - const _sg_image_t* color_img = color_images[i]; - SOKOL_ASSERT(0 == atts->d3d11.colors[i].view.rtv); - const bool msaa = color_img->cmn.sample_count > 1; - D3D11_RENDER_TARGET_VIEW_DESC d3d11_rtv_desc; - _sg_clear(&d3d11_rtv_desc, sizeof(d3d11_rtv_desc)); - d3d11_rtv_desc.Format = _sg_d3d11_rtv_pixel_format(color_img->cmn.pixel_format); - if (color_img->cmn.type == SG_IMAGETYPE_2D) { - if (msaa) { - d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; - } else { - d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - d3d11_rtv_desc.Texture2D.MipSlice = (UINT)cmn_color_att->mip_level; - } - } else if ((color_img->cmn.type == SG_IMAGETYPE_CUBE) || (color_img->cmn.type == SG_IMAGETYPE_ARRAY)) { - if (msaa) { - d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; - d3d11_rtv_desc.Texture2DMSArray.FirstArraySlice = (UINT)cmn_color_att->slice; - d3d11_rtv_desc.Texture2DMSArray.ArraySize = 1; - } else { - d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - d3d11_rtv_desc.Texture2DArray.MipSlice = (UINT)cmn_color_att->mip_level; - d3d11_rtv_desc.Texture2DArray.FirstArraySlice = (UINT)cmn_color_att->slice; - d3d11_rtv_desc.Texture2DArray.ArraySize = 1; - } - } else { - SOKOL_ASSERT(color_img->cmn.type == SG_IMAGETYPE_3D); - SOKOL_ASSERT(!msaa); - d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - d3d11_rtv_desc.Texture3D.MipSlice = (UINT)cmn_color_att->mip_level; - d3d11_rtv_desc.Texture3D.FirstWSlice = (UINT)cmn_color_att->slice; - d3d11_rtv_desc.Texture3D.WSize = 1; - } - SOKOL_ASSERT(color_img->d3d11.res); - HRESULT hr = _sg_d3d11_CreateRenderTargetView(_sg.d3d11.dev, color_img->d3d11.res, &d3d11_rtv_desc, &atts->d3d11.colors[i].view.rtv); - if (!(SUCCEEDED(hr) && atts->d3d11.colors[i].view.rtv)) { - _SG_ERROR(D3D11_CREATE_RTV_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(atts->d3d11.colors[i].view.rtv, desc->label); - } - SOKOL_ASSERT(0 == atts->d3d11.depth_stencil.view.dsv); - if (ds_desc->image.id != SG_INVALID_ID) { - const _sg_attachment_common_t* cmn_ds_att = &atts->cmn.depth_stencil; - const bool msaa = ds_img->cmn.sample_count > 1; - D3D11_DEPTH_STENCIL_VIEW_DESC d3d11_dsv_desc; - _sg_clear(&d3d11_dsv_desc, sizeof(d3d11_dsv_desc)); - d3d11_dsv_desc.Format = _sg_d3d11_dsv_pixel_format(ds_img->cmn.pixel_format); - SOKOL_ASSERT(ds_img && ds_img->cmn.type != SG_IMAGETYPE_3D); - if (ds_img->cmn.type == SG_IMAGETYPE_2D) { - if (msaa) { - d3d11_dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; - } else { - d3d11_dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - d3d11_dsv_desc.Texture2D.MipSlice = (UINT)cmn_ds_att->mip_level; - } - } else if ((ds_img->cmn.type == SG_IMAGETYPE_CUBE) || (ds_img->cmn.type == SG_IMAGETYPE_ARRAY)) { - if (msaa) { - d3d11_dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; - d3d11_dsv_desc.Texture2DMSArray.FirstArraySlice = (UINT)cmn_ds_att->slice; - d3d11_dsv_desc.Texture2DMSArray.ArraySize = 1; - } else { - d3d11_dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; - d3d11_dsv_desc.Texture2DArray.MipSlice = (UINT)cmn_ds_att->mip_level; - d3d11_dsv_desc.Texture2DArray.FirstArraySlice = (UINT)cmn_ds_att->slice; - d3d11_dsv_desc.Texture2DArray.ArraySize = 1; - } - } - SOKOL_ASSERT(ds_img->d3d11.res); - HRESULT hr = _sg_d3d11_CreateDepthStencilView(_sg.d3d11.dev, ds_img->d3d11.res, &d3d11_dsv_desc, &atts->d3d11.depth_stencil.view.dsv); - if (!(SUCCEEDED(hr) && atts->d3d11.depth_stencil.view.dsv)) { - _SG_ERROR(D3D11_CREATE_DSV_FAILED); - return SG_RESOURCESTATE_FAILED; - } - _sg_d3d11_setlabel(atts->d3d11.depth_stencil.view.dsv, desc->label); - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_d3d11_discard_attachments(_sg_attachments_t* atts) { - SOKOL_ASSERT(atts); - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (atts->d3d11.colors[i].view.rtv) { - _sg_d3d11_Release(atts->d3d11.colors[i].view.rtv); - } - if (atts->d3d11.resolves[i].view.rtv) { - _sg_d3d11_Release(atts->d3d11.resolves[i].view.rtv); - } - } - if (atts->d3d11.depth_stencil.view.dsv) { - _sg_d3d11_Release(atts->d3d11.depth_stencil.view.dsv); - } -} - -_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_attachments_color_image(const _sg_attachments_t* atts, int index) { - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return atts->d3d11.colors[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_attachments_resolve_image(const _sg_attachments_t* atts, int index) { - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return atts->d3d11.resolves[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_attachments_ds_image(const _sg_attachments_t* atts) { - SOKOL_ASSERT(atts); - return atts->d3d11.depth_stencil.image; -} - -_SOKOL_PRIVATE void _sg_d3d11_begin_pass(const sg_pass* pass) { - SOKOL_ASSERT(pass); - - const _sg_attachments_t* atts = _sg.cur_pass.atts; - const sg_swapchain* swapchain = &pass->swapchain; - const sg_pass_action* action = &pass->action; - - int num_rtvs = 0; - ID3D11RenderTargetView* rtvs[SG_MAX_COLOR_ATTACHMENTS] = { 0 }; - ID3D11DepthStencilView* dsv = 0; - _sg.d3d11.cur_pass.render_view = 0; - _sg.d3d11.cur_pass.resolve_view = 0; - if (atts) { - num_rtvs = atts->cmn.num_colors; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - rtvs[i] = atts->d3d11.colors[i].view.rtv; - } - dsv = atts->d3d11.depth_stencil.view.dsv; - } else { - // NOTE: depth-stencil-view is optional - SOKOL_ASSERT(swapchain->d3d11.render_view); - num_rtvs = 1; - rtvs[0] = (ID3D11RenderTargetView*) swapchain->d3d11.render_view; - dsv = (ID3D11DepthStencilView*) swapchain->d3d11.depth_stencil_view; - _sg.d3d11.cur_pass.render_view = (ID3D11RenderTargetView*) swapchain->d3d11.render_view; - _sg.d3d11.cur_pass.resolve_view = (ID3D11RenderTargetView*) swapchain->d3d11.resolve_view; - } - // apply the render-target- and depth-stencil-views - _sg_d3d11_OMSetRenderTargets(_sg.d3d11.ctx, SG_MAX_COLOR_ATTACHMENTS, rtvs, dsv); - _sg_stats_add(d3d11.pass.num_om_set_render_targets, 1); - - // set viewport and scissor rect to cover whole screen - D3D11_VIEWPORT vp; - _sg_clear(&vp, sizeof(vp)); - vp.Width = (FLOAT) _sg.cur_pass.width; - vp.Height = (FLOAT) _sg.cur_pass.height; - vp.MaxDepth = 1.0f; - _sg_d3d11_RSSetViewports(_sg.d3d11.ctx, 1, &vp); - D3D11_RECT rect; - rect.left = 0; - rect.top = 0; - rect.right = _sg.cur_pass.width; - rect.bottom = _sg.cur_pass.height; - _sg_d3d11_RSSetScissorRects(_sg.d3d11.ctx, 1, &rect); - - // perform clear action - for (int i = 0; i < num_rtvs; i++) { - if (action->colors[i].load_action == SG_LOADACTION_CLEAR) { - _sg_d3d11_ClearRenderTargetView(_sg.d3d11.ctx, rtvs[i], (float*)&action->colors[i].clear_value); - _sg_stats_add(d3d11.pass.num_clear_render_target_view, 1); - } - } - UINT ds_flags = 0; - if (action->depth.load_action == SG_LOADACTION_CLEAR) { - ds_flags |= D3D11_CLEAR_DEPTH; - } - if (action->stencil.load_action == SG_LOADACTION_CLEAR) { - ds_flags |= D3D11_CLEAR_STENCIL; - } - if ((0 != ds_flags) && dsv) { - _sg_d3d11_ClearDepthStencilView(_sg.d3d11.ctx, dsv, ds_flags, action->depth.clear_value, action->stencil.clear_value); - _sg_stats_add(d3d11.pass.num_clear_depth_stencil_view, 1); - } -} - -// D3D11CalcSubresource only exists for C++ -_SOKOL_PRIVATE UINT _sg_d3d11_calcsubresource(UINT mip_slice, UINT array_slice, UINT mip_levels) { - return mip_slice + array_slice * mip_levels; -} - -_SOKOL_PRIVATE void _sg_d3d11_end_pass(void) { - SOKOL_ASSERT(_sg.d3d11.ctx); - - // need to resolve MSAA render attachments into texture? - if (_sg.cur_pass.atts_id.id != SG_INVALID_ID) { - // ...for offscreen pass... - SOKOL_ASSERT(_sg.cur_pass.atts && _sg.cur_pass.atts->slot.id == _sg.cur_pass.atts_id.id); - for (int i = 0; i < _sg.cur_pass.atts->cmn.num_colors; i++) { - const _sg_image_t* resolve_img = _sg.cur_pass.atts->d3d11.resolves[i].image; - if (resolve_img) { - const _sg_image_t* color_img = _sg.cur_pass.atts->d3d11.colors[i].image; - const _sg_attachment_common_t* cmn_color_att = &_sg.cur_pass.atts->cmn.colors[i]; - const _sg_attachment_common_t* cmn_resolve_att = &_sg.cur_pass.atts->cmn.resolves[i]; - SOKOL_ASSERT(resolve_img->slot.id == cmn_resolve_att->image_id.id); - SOKOL_ASSERT(color_img && (color_img->slot.id == cmn_color_att->image_id.id)); - SOKOL_ASSERT(color_img->cmn.sample_count > 1); - SOKOL_ASSERT(resolve_img->cmn.sample_count == 1); - const UINT src_subres = _sg_d3d11_calcsubresource( - (UINT)cmn_color_att->mip_level, - (UINT)cmn_color_att->slice, - (UINT)color_img->cmn.num_mipmaps); - const UINT dst_subres = _sg_d3d11_calcsubresource( - (UINT)cmn_resolve_att->mip_level, - (UINT)cmn_resolve_att->slice, - (UINT)resolve_img->cmn.num_mipmaps); - _sg_d3d11_ResolveSubresource(_sg.d3d11.ctx, - resolve_img->d3d11.res, - dst_subres, - color_img->d3d11.res, - src_subres, - color_img->d3d11.format); - _sg_stats_add(d3d11.pass.num_resolve_subresource, 1); - } - } - } else { - // ...for swapchain pass... - if (_sg.d3d11.cur_pass.resolve_view) { - SOKOL_ASSERT(_sg.d3d11.cur_pass.render_view); - SOKOL_ASSERT(_sg.cur_pass.swapchain.sample_count > 1); - SOKOL_ASSERT(_sg.cur_pass.swapchain.color_fmt > SG_PIXELFORMAT_NONE); - ID3D11Resource* d3d11_render_res = 0; - ID3D11Resource* d3d11_resolve_res = 0; - _sg_d3d11_GetResource((ID3D11View*)_sg.d3d11.cur_pass.render_view, &d3d11_render_res); - _sg_d3d11_GetResource((ID3D11View*)_sg.d3d11.cur_pass.resolve_view, &d3d11_resolve_res); - SOKOL_ASSERT(d3d11_render_res); - SOKOL_ASSERT(d3d11_resolve_res); - const sg_pixel_format color_fmt = _sg.cur_pass.swapchain.color_fmt; - _sg_d3d11_ResolveSubresource(_sg.d3d11.ctx, d3d11_resolve_res, 0, d3d11_render_res, 0, _sg_d3d11_rtv_pixel_format(color_fmt)); - _sg_d3d11_Release(d3d11_render_res); - _sg_d3d11_Release(d3d11_resolve_res); - _sg_stats_add(d3d11.pass.num_resolve_subresource, 1); - } - } - _sg.d3d11.cur_pass.render_view = 0; - _sg.d3d11.cur_pass.resolve_view = 0; - _sg.d3d11.cur_pipeline = 0; - _sg.d3d11.cur_pipeline_id.id = SG_INVALID_ID; - _sg_d3d11_clear_state(); -} - -_SOKOL_PRIVATE void _sg_d3d11_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.d3d11.ctx); - D3D11_VIEWPORT vp; - vp.TopLeftX = (FLOAT) x; - vp.TopLeftY = (FLOAT) (origin_top_left ? y : (_sg.cur_pass.height - (y + h))); - vp.Width = (FLOAT) w; - vp.Height = (FLOAT) h; - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - _sg_d3d11_RSSetViewports(_sg.d3d11.ctx, 1, &vp); -} - -_SOKOL_PRIVATE void _sg_d3d11_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.d3d11.ctx); - D3D11_RECT rect; - rect.left = x; - rect.top = (origin_top_left ? y : (_sg.cur_pass.height - (y + h))); - rect.right = x + w; - rect.bottom = origin_top_left ? (y + h) : (_sg.cur_pass.height - y); - _sg_d3d11_RSSetScissorRects(_sg.d3d11.ctx, 1, &rect); -} - -_SOKOL_PRIVATE void _sg_d3d11_apply_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); - SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(pip->d3d11.rs && pip->d3d11.bs && pip->d3d11.dss); - - _sg.d3d11.cur_pipeline = pip; - _sg.d3d11.cur_pipeline_id.id = pip->slot.id; - _sg.d3d11.use_indexed_draw = (pip->d3d11.index_format != DXGI_FORMAT_UNKNOWN); - _sg.d3d11.use_instanced_draw = pip->cmn.use_instanced_draw; - - _sg_d3d11_RSSetState(_sg.d3d11.ctx, pip->d3d11.rs); - _sg_d3d11_OMSetDepthStencilState(_sg.d3d11.ctx, pip->d3d11.dss, pip->d3d11.stencil_ref); - _sg_d3d11_OMSetBlendState(_sg.d3d11.ctx, pip->d3d11.bs, (float*)&pip->cmn.blend_color, 0xFFFFFFFF); - _sg_d3d11_IASetPrimitiveTopology(_sg.d3d11.ctx, pip->d3d11.topology); - _sg_d3d11_IASetInputLayout(_sg.d3d11.ctx, pip->d3d11.il); - _sg_d3d11_VSSetShader(_sg.d3d11.ctx, pip->shader->d3d11.vs, NULL, 0); - _sg_d3d11_VSSetConstantBuffers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_UBS, pip->shader->d3d11.stage[SG_SHADERSTAGE_VS].cbufs); - _sg_d3d11_PSSetShader(_sg.d3d11.ctx, pip->shader->d3d11.fs, NULL, 0); - _sg_d3d11_PSSetConstantBuffers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_UBS, pip->shader->d3d11.stage[SG_SHADERSTAGE_FS].cbufs); - _sg_stats_add(d3d11.pipeline.num_rs_set_state, 1); - _sg_stats_add(d3d11.pipeline.num_om_set_depth_stencil_state, 1); - _sg_stats_add(d3d11.pipeline.num_om_set_blend_state, 1); - _sg_stats_add(d3d11.pipeline.num_ia_set_primitive_topology, 1); - _sg_stats_add(d3d11.pipeline.num_ia_set_input_layout, 1); - _sg_stats_add(d3d11.pipeline.num_vs_set_shader, 1); - _sg_stats_add(d3d11.pipeline.num_vs_set_constant_buffers, 1); - _sg_stats_add(d3d11.pipeline.num_ps_set_shader, 1); - _sg_stats_add(d3d11.pipeline.num_ps_set_constant_buffers, 1); -} - -_SOKOL_PRIVATE bool _sg_d3d11_apply_bindings(_sg_bindings_t* bnd) { - SOKOL_ASSERT(bnd); - SOKOL_ASSERT(bnd->pip); - SOKOL_ASSERT(_sg.d3d11.ctx); - - // gather all the D3D11 resources into arrays - ID3D11Buffer* d3d11_ib = bnd->ib ? bnd->ib->d3d11.buf : 0; - ID3D11Buffer* d3d11_vbs[SG_MAX_VERTEX_BUFFERS] = {0}; - UINT d3d11_vb_offsets[SG_MAX_VERTEX_BUFFERS] = {0}; - ID3D11ShaderResourceView* d3d11_vs_srvs[_SG_D3D11_MAX_SHADERSTAGE_SRVS] = {0}; - ID3D11ShaderResourceView* d3d11_fs_srvs[_SG_D3D11_MAX_SHADERSTAGE_SRVS] = {0}; - ID3D11SamplerState* d3d11_vs_smps[SG_MAX_SHADERSTAGE_SAMPLERS] = {0}; - ID3D11SamplerState* d3d11_fs_smps[SG_MAX_SHADERSTAGE_SAMPLERS] = {0}; - for (int i = 0; i < bnd->num_vbs; i++) { - SOKOL_ASSERT(bnd->vbs[i]->d3d11.buf); - d3d11_vbs[i] = bnd->vbs[i]->d3d11.buf; - d3d11_vb_offsets[i] = (UINT)bnd->vb_offsets[i]; - } - for (int i = 0; i < bnd->num_vs_imgs; i++) { - SOKOL_ASSERT(bnd->vs_imgs[i]->d3d11.srv); - d3d11_vs_srvs[_SG_D3D11_SHADERSTAGE_IMAGE_SRV_OFFSET + i] = bnd->vs_imgs[i]->d3d11.srv; - } - for (int i = 0; i < bnd->num_vs_sbufs; i++) { - SOKOL_ASSERT(bnd->vs_sbufs[i]->d3d11.srv); - d3d11_vs_srvs[_SG_D3D11_SHADERSTAGE_BUFFER_SRV_OFFSET + i] = bnd->vs_sbufs[i]->d3d11.srv; - } - for (int i = 0; i < bnd->num_fs_imgs; i++) { - SOKOL_ASSERT(bnd->fs_imgs[i]->d3d11.srv); - d3d11_fs_srvs[_SG_D3D11_SHADERSTAGE_IMAGE_SRV_OFFSET + i] = bnd->fs_imgs[i]->d3d11.srv; - } - for (int i = 0; i < bnd->num_fs_sbufs; i++) { - SOKOL_ASSERT(bnd->fs_sbufs[i]->d3d11.srv); - d3d11_fs_srvs[_SG_D3D11_SHADERSTAGE_BUFFER_SRV_OFFSET + i] = bnd->fs_sbufs[i]->d3d11.srv; - } - for (int i = 0; i < bnd->num_vs_smps; i++) { - SOKOL_ASSERT(bnd->vs_smps[i]->d3d11.smp); - d3d11_vs_smps[i] = bnd->vs_smps[i]->d3d11.smp; - } - for (int i = 0; i < bnd->num_fs_smps; i++) { - SOKOL_ASSERT(bnd->fs_smps[i]->d3d11.smp); - d3d11_fs_smps[i] = bnd->fs_smps[i]->d3d11.smp; - } - _sg_d3d11_IASetVertexBuffers(_sg.d3d11.ctx, 0, SG_MAX_VERTEX_BUFFERS, d3d11_vbs, bnd->pip->d3d11.vb_strides, d3d11_vb_offsets); - _sg_d3d11_IASetIndexBuffer(_sg.d3d11.ctx, d3d11_ib, bnd->pip->d3d11.index_format, (UINT)bnd->ib_offset); - _sg_d3d11_VSSetShaderResources(_sg.d3d11.ctx, 0, _SG_D3D11_MAX_SHADERSTAGE_SRVS, d3d11_vs_srvs); - _sg_d3d11_PSSetShaderResources(_sg.d3d11.ctx, 0, _SG_D3D11_MAX_SHADERSTAGE_SRVS, d3d11_fs_srvs); - _sg_d3d11_VSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_SAMPLERS, d3d11_vs_smps); - _sg_d3d11_PSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_SAMPLERS, d3d11_fs_smps); - _sg_stats_add(d3d11.bindings.num_ia_set_vertex_buffers, 1); - _sg_stats_add(d3d11.bindings.num_ia_set_index_buffer, 1); - _sg_stats_add(d3d11.bindings.num_vs_set_shader_resources, 1); - _sg_stats_add(d3d11.bindings.num_ps_set_shader_resources, 1); - _sg_stats_add(d3d11.bindings.num_vs_set_samplers, 1); - _sg_stats_add(d3d11.bindings.num_ps_set_samplers, 1); - return true; -} - -_SOKOL_PRIVATE void _sg_d3d11_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { - SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(_sg.d3d11.cur_pipeline && _sg.d3d11.cur_pipeline->slot.id == _sg.d3d11.cur_pipeline_id.id); - SOKOL_ASSERT(_sg.d3d11.cur_pipeline->shader && _sg.d3d11.cur_pipeline->shader->slot.id == _sg.d3d11.cur_pipeline->cmn.shader_id.id); - SOKOL_ASSERT(ub_index < _sg.d3d11.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); - SOKOL_ASSERT(data->size == _sg.d3d11.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); - ID3D11Buffer* cb = _sg.d3d11.cur_pipeline->shader->d3d11.stage[stage_index].cbufs[ub_index]; - SOKOL_ASSERT(cb); - _sg_d3d11_UpdateSubresource(_sg.d3d11.ctx, (ID3D11Resource*)cb, 0, NULL, data->ptr, 0, 0); - _sg_stats_add(d3d11.uniforms.num_update_subresource, 1); -} - -_SOKOL_PRIVATE void _sg_d3d11_draw(int base_element, int num_elements, int num_instances) { - const bool use_instanced_draw = (num_instances > 1) || (_sg.d3d11.use_instanced_draw); - if (_sg.d3d11.use_indexed_draw) { - if (use_instanced_draw) { - _sg_d3d11_DrawIndexedInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0, 0); - _sg_stats_add(d3d11.draw.num_draw_indexed_instanced, 1); - } else { - _sg_d3d11_DrawIndexed(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element, 0); - _sg_stats_add(d3d11.draw.num_draw_indexed, 1); - } - } else { - if (use_instanced_draw) { - _sg_d3d11_DrawInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0); - _sg_stats_add(d3d11.draw.num_draw_instanced, 1); - } else { - _sg_d3d11_Draw(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element); - _sg_stats_add(d3d11.draw.num_draw, 1); - } - } -} - -_SOKOL_PRIVATE void _sg_d3d11_commit(void) { - // empty -} - -_SOKOL_PRIVATE void _sg_d3d11_update_buffer(_sg_buffer_t* buf, const sg_range* data) { - SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); - SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(buf->d3d11.buf); - D3D11_MAPPED_SUBRESOURCE d3d11_msr; - HRESULT hr = _sg_d3d11_Map(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &d3d11_msr); - _sg_stats_add(d3d11.num_map, 1); - if (SUCCEEDED(hr)) { - memcpy(d3d11_msr.pData, data->ptr, data->size); - _sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0); - _sg_stats_add(d3d11.num_unmap, 1); - } else { - _SG_ERROR(D3D11_MAP_FOR_UPDATE_BUFFER_FAILED); - } -} - -_SOKOL_PRIVATE void _sg_d3d11_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { - SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); - SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(buf->d3d11.buf); - D3D11_MAP map_type = new_frame ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE; - D3D11_MAPPED_SUBRESOURCE d3d11_msr; - HRESULT hr = _sg_d3d11_Map(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0, map_type, 0, &d3d11_msr); - _sg_stats_add(d3d11.num_map, 1); - if (SUCCEEDED(hr)) { - uint8_t* dst_ptr = (uint8_t*)d3d11_msr.pData + buf->cmn.append_pos; - memcpy(dst_ptr, data->ptr, data->size); - _sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0); - _sg_stats_add(d3d11.num_unmap, 1); - } else { - _SG_ERROR(D3D11_MAP_FOR_APPEND_BUFFER_FAILED); - } -} - -// see: https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-subresources -// also see: https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-d3d11calcsubresource -_SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data* data) { - SOKOL_ASSERT(img && data); - SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(img->d3d11.res); - const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; - const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices:1; - const int num_depth_slices = (img->cmn.type == SG_IMAGETYPE_3D) ? img->cmn.num_slices:1; - UINT subres_index = 0; - HRESULT hr; - D3D11_MAPPED_SUBRESOURCE d3d11_msr; - for (int face_index = 0; face_index < num_faces; face_index++) { - for (int slice_index = 0; slice_index < num_slices; slice_index++) { - for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, subres_index++) { - SOKOL_ASSERT(subres_index < (SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS)); - const int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); - const int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); - const int src_row_pitch = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); - const int src_depth_pitch = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1); - const sg_range* subimg_data = &(data->subimage[face_index][mip_index]); - const size_t slice_size = subimg_data->size / (size_t)num_slices; - SOKOL_ASSERT(slice_size == (size_t)(src_depth_pitch * num_depth_slices)); - const size_t slice_offset = slice_size * (size_t)slice_index; - const uint8_t* slice_ptr = ((const uint8_t*)subimg_data->ptr) + slice_offset; - hr = _sg_d3d11_Map(_sg.d3d11.ctx, img->d3d11.res, subres_index, D3D11_MAP_WRITE_DISCARD, 0, &d3d11_msr); - _sg_stats_add(d3d11.num_map, 1); - if (SUCCEEDED(hr)) { - const uint8_t* src_ptr = slice_ptr; - uint8_t* dst_ptr = (uint8_t*)d3d11_msr.pData; - for (int depth_index = 0; depth_index < num_depth_slices; depth_index++) { - if (src_row_pitch == (int)d3d11_msr.RowPitch) { - const size_t copy_size = slice_size / (size_t)num_depth_slices; - SOKOL_ASSERT((copy_size * (size_t)num_depth_slices) == slice_size); - memcpy(dst_ptr, src_ptr, copy_size); - } else { - SOKOL_ASSERT(src_row_pitch < (int)d3d11_msr.RowPitch); - const uint8_t* src_row_ptr = src_ptr; - uint8_t* dst_row_ptr = dst_ptr; - for (int row_index = 0; row_index < mip_height; row_index++) { - memcpy(dst_row_ptr, src_row_ptr, (size_t)src_row_pitch); - src_row_ptr += src_row_pitch; - dst_row_ptr += d3d11_msr.RowPitch; - } - } - src_ptr += src_depth_pitch; - dst_ptr += d3d11_msr.DepthPitch; - } - _sg_d3d11_Unmap(_sg.d3d11.ctx, img->d3d11.res, subres_index); - _sg_stats_add(d3d11.num_unmap, 1); - } else { - _SG_ERROR(D3D11_MAP_FOR_UPDATE_IMAGE_FAILED); - } - } - } - } -} - -// ███ ███ ███████ ████████ █████ ██ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ -// ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██ ████ ██ █████ ██ ███████ ██ ██████ ███████ ██ █████ █████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██ ███████ ██████ ██ ██ ██████ ██ ██ ███████ ██ ████ ██████ -// -// >>metal backend -#elif defined(SOKOL_METAL) - -#if __has_feature(objc_arc) -#define _SG_OBJC_RETAIN(obj) { } -#define _SG_OBJC_RELEASE(obj) { obj = nil; } -#else -#define _SG_OBJC_RETAIN(obj) { [obj retain]; } -#define _SG_OBJC_RELEASE(obj) { [obj release]; obj = nil; } -#endif - -//-- enum translation functions ------------------------------------------------ -_SOKOL_PRIVATE MTLLoadAction _sg_mtl_load_action(sg_load_action a) { - switch (a) { - case SG_LOADACTION_CLEAR: return MTLLoadActionClear; - case SG_LOADACTION_LOAD: return MTLLoadActionLoad; - case SG_LOADACTION_DONTCARE: return MTLLoadActionDontCare; - default: SOKOL_UNREACHABLE; return (MTLLoadAction)0; - } -} - -_SOKOL_PRIVATE MTLStoreAction _sg_mtl_store_action(sg_store_action a, bool resolve) { - switch (a) { - case SG_STOREACTION_STORE: - if (resolve) { - return MTLStoreActionStoreAndMultisampleResolve; - } else { - return MTLStoreActionStore; - } - break; - case SG_STOREACTION_DONTCARE: - if (resolve) { - return MTLStoreActionMultisampleResolve; - } else { - return MTLStoreActionDontCare; - } - break; - default: SOKOL_UNREACHABLE; return (MTLStoreAction)0; - } -} - -_SOKOL_PRIVATE MTLResourceOptions _sg_mtl_resource_options_storage_mode_managed_or_shared(void) { - #if defined(_SG_TARGET_MACOS) - if (_sg.mtl.use_shared_storage_mode) { - return MTLResourceStorageModeShared; - } else { - return MTLResourceStorageModeManaged; - } - #else - // MTLResourceStorageModeManaged is not even defined on iOS SDK - return MTLResourceStorageModeShared; - #endif -} - -_SOKOL_PRIVATE MTLResourceOptions _sg_mtl_buffer_resource_options(sg_usage usg) { - switch (usg) { - case SG_USAGE_IMMUTABLE: - return _sg_mtl_resource_options_storage_mode_managed_or_shared(); - case SG_USAGE_DYNAMIC: - case SG_USAGE_STREAM: - return MTLResourceCPUCacheModeWriteCombined | _sg_mtl_resource_options_storage_mode_managed_or_shared(); - default: - SOKOL_UNREACHABLE; - return 0; - } -} - -_SOKOL_PRIVATE MTLVertexStepFunction _sg_mtl_step_function(sg_vertex_step step) { - switch (step) { - case SG_VERTEXSTEP_PER_VERTEX: return MTLVertexStepFunctionPerVertex; - case SG_VERTEXSTEP_PER_INSTANCE: return MTLVertexStepFunctionPerInstance; - default: SOKOL_UNREACHABLE; return (MTLVertexStepFunction)0; - } -} - -_SOKOL_PRIVATE MTLVertexFormat _sg_mtl_vertex_format(sg_vertex_format fmt) { - switch (fmt) { - case SG_VERTEXFORMAT_FLOAT: return MTLVertexFormatFloat; - case SG_VERTEXFORMAT_FLOAT2: return MTLVertexFormatFloat2; - case SG_VERTEXFORMAT_FLOAT3: return MTLVertexFormatFloat3; - case SG_VERTEXFORMAT_FLOAT4: return MTLVertexFormatFloat4; - case SG_VERTEXFORMAT_BYTE4: return MTLVertexFormatChar4; - case SG_VERTEXFORMAT_BYTE4N: return MTLVertexFormatChar4Normalized; - case SG_VERTEXFORMAT_UBYTE4: return MTLVertexFormatUChar4; - case SG_VERTEXFORMAT_UBYTE4N: return MTLVertexFormatUChar4Normalized; - case SG_VERTEXFORMAT_SHORT2: return MTLVertexFormatShort2; - case SG_VERTEXFORMAT_SHORT2N: return MTLVertexFormatShort2Normalized; - case SG_VERTEXFORMAT_USHORT2N: return MTLVertexFormatUShort2Normalized; - case SG_VERTEXFORMAT_SHORT4: return MTLVertexFormatShort4; - case SG_VERTEXFORMAT_SHORT4N: return MTLVertexFormatShort4Normalized; - case SG_VERTEXFORMAT_USHORT4N: return MTLVertexFormatUShort4Normalized; - case SG_VERTEXFORMAT_UINT10_N2: return MTLVertexFormatUInt1010102Normalized; - case SG_VERTEXFORMAT_HALF2: return MTLVertexFormatHalf2; - case SG_VERTEXFORMAT_HALF4: return MTLVertexFormatHalf4; - default: SOKOL_UNREACHABLE; return (MTLVertexFormat)0; - } -} - -_SOKOL_PRIVATE MTLPrimitiveType _sg_mtl_primitive_type(sg_primitive_type t) { - switch (t) { - case SG_PRIMITIVETYPE_POINTS: return MTLPrimitiveTypePoint; - case SG_PRIMITIVETYPE_LINES: return MTLPrimitiveTypeLine; - case SG_PRIMITIVETYPE_LINE_STRIP: return MTLPrimitiveTypeLineStrip; - case SG_PRIMITIVETYPE_TRIANGLES: return MTLPrimitiveTypeTriangle; - case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return MTLPrimitiveTypeTriangleStrip; - default: SOKOL_UNREACHABLE; return (MTLPrimitiveType)0; - } -} - -_SOKOL_PRIVATE MTLPixelFormat _sg_mtl_pixel_format(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_R8: return MTLPixelFormatR8Unorm; - case SG_PIXELFORMAT_R8SN: return MTLPixelFormatR8Snorm; - case SG_PIXELFORMAT_R8UI: return MTLPixelFormatR8Uint; - case SG_PIXELFORMAT_R8SI: return MTLPixelFormatR8Sint; - case SG_PIXELFORMAT_R16: return MTLPixelFormatR16Unorm; - case SG_PIXELFORMAT_R16SN: return MTLPixelFormatR16Snorm; - case SG_PIXELFORMAT_R16UI: return MTLPixelFormatR16Uint; - case SG_PIXELFORMAT_R16SI: return MTLPixelFormatR16Sint; - case SG_PIXELFORMAT_R16F: return MTLPixelFormatR16Float; - case SG_PIXELFORMAT_RG8: return MTLPixelFormatRG8Unorm; - case SG_PIXELFORMAT_RG8SN: return MTLPixelFormatRG8Snorm; - case SG_PIXELFORMAT_RG8UI: return MTLPixelFormatRG8Uint; - case SG_PIXELFORMAT_RG8SI: return MTLPixelFormatRG8Sint; - case SG_PIXELFORMAT_R32UI: return MTLPixelFormatR32Uint; - case SG_PIXELFORMAT_R32SI: return MTLPixelFormatR32Sint; - case SG_PIXELFORMAT_R32F: return MTLPixelFormatR32Float; - case SG_PIXELFORMAT_RG16: return MTLPixelFormatRG16Unorm; - case SG_PIXELFORMAT_RG16SN: return MTLPixelFormatRG16Snorm; - case SG_PIXELFORMAT_RG16UI: return MTLPixelFormatRG16Uint; - case SG_PIXELFORMAT_RG16SI: return MTLPixelFormatRG16Sint; - case SG_PIXELFORMAT_RG16F: return MTLPixelFormatRG16Float; - case SG_PIXELFORMAT_RGBA8: return MTLPixelFormatRGBA8Unorm; - case SG_PIXELFORMAT_SRGB8A8: return MTLPixelFormatRGBA8Unorm_sRGB; - case SG_PIXELFORMAT_RGBA8SN: return MTLPixelFormatRGBA8Snorm; - case SG_PIXELFORMAT_RGBA8UI: return MTLPixelFormatRGBA8Uint; - case SG_PIXELFORMAT_RGBA8SI: return MTLPixelFormatRGBA8Sint; - case SG_PIXELFORMAT_BGRA8: return MTLPixelFormatBGRA8Unorm; - case SG_PIXELFORMAT_RGB10A2: return MTLPixelFormatRGB10A2Unorm; - case SG_PIXELFORMAT_RG11B10F: return MTLPixelFormatRG11B10Float; - case SG_PIXELFORMAT_RGB9E5: return MTLPixelFormatRGB9E5Float; - case SG_PIXELFORMAT_RG32UI: return MTLPixelFormatRG32Uint; - case SG_PIXELFORMAT_RG32SI: return MTLPixelFormatRG32Sint; - case SG_PIXELFORMAT_RG32F: return MTLPixelFormatRG32Float; - case SG_PIXELFORMAT_RGBA16: return MTLPixelFormatRGBA16Unorm; - case SG_PIXELFORMAT_RGBA16SN: return MTLPixelFormatRGBA16Snorm; - case SG_PIXELFORMAT_RGBA16UI: return MTLPixelFormatRGBA16Uint; - case SG_PIXELFORMAT_RGBA16SI: return MTLPixelFormatRGBA16Sint; - case SG_PIXELFORMAT_RGBA16F: return MTLPixelFormatRGBA16Float; - case SG_PIXELFORMAT_RGBA32UI: return MTLPixelFormatRGBA32Uint; - case SG_PIXELFORMAT_RGBA32SI: return MTLPixelFormatRGBA32Sint; - case SG_PIXELFORMAT_RGBA32F: return MTLPixelFormatRGBA32Float; - case SG_PIXELFORMAT_DEPTH: return MTLPixelFormatDepth32Float; - case SG_PIXELFORMAT_DEPTH_STENCIL: return MTLPixelFormatDepth32Float_Stencil8; - #if defined(_SG_TARGET_MACOS) - case SG_PIXELFORMAT_BC1_RGBA: return MTLPixelFormatBC1_RGBA; - case SG_PIXELFORMAT_BC2_RGBA: return MTLPixelFormatBC2_RGBA; - case SG_PIXELFORMAT_BC3_RGBA: return MTLPixelFormatBC3_RGBA; - case SG_PIXELFORMAT_BC3_SRGBA: return MTLPixelFormatBC3_RGBA_sRGB; - case SG_PIXELFORMAT_BC4_R: return MTLPixelFormatBC4_RUnorm; - case SG_PIXELFORMAT_BC4_RSN: return MTLPixelFormatBC4_RSnorm; - case SG_PIXELFORMAT_BC5_RG: return MTLPixelFormatBC5_RGUnorm; - case SG_PIXELFORMAT_BC5_RGSN: return MTLPixelFormatBC5_RGSnorm; - case SG_PIXELFORMAT_BC6H_RGBF: return MTLPixelFormatBC6H_RGBFloat; - case SG_PIXELFORMAT_BC6H_RGBUF: return MTLPixelFormatBC6H_RGBUfloat; - case SG_PIXELFORMAT_BC7_RGBA: return MTLPixelFormatBC7_RGBAUnorm; - case SG_PIXELFORMAT_BC7_SRGBA: return MTLPixelFormatBC7_RGBAUnorm_sRGB; - #else - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: return MTLPixelFormatPVRTC_RGB_2BPP; - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: return MTLPixelFormatPVRTC_RGB_4BPP; - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: return MTLPixelFormatPVRTC_RGBA_2BPP; - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: return MTLPixelFormatPVRTC_RGBA_4BPP; - case SG_PIXELFORMAT_ETC2_RGB8: return MTLPixelFormatETC2_RGB8; - case SG_PIXELFORMAT_ETC2_SRGB8: return MTLPixelFormatETC2_RGB8_sRGB; - case SG_PIXELFORMAT_ETC2_RGB8A1: return MTLPixelFormatETC2_RGB8A1; - case SG_PIXELFORMAT_ETC2_RGBA8: return MTLPixelFormatEAC_RGBA8; - case SG_PIXELFORMAT_ETC2_SRGB8A8: return MTLPixelFormatEAC_RGBA8_sRGB; - case SG_PIXELFORMAT_EAC_R11: return MTLPixelFormatEAC_R11Unorm; - case SG_PIXELFORMAT_EAC_R11SN: return MTLPixelFormatEAC_R11Snorm; - case SG_PIXELFORMAT_EAC_RG11: return MTLPixelFormatEAC_RG11Unorm; - case SG_PIXELFORMAT_EAC_RG11SN: return MTLPixelFormatEAC_RG11Snorm; - case SG_PIXELFORMAT_ASTC_4x4_RGBA: return MTLPixelFormatASTC_4x4_LDR; - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return MTLPixelFormatASTC_4x4_sRGB; - #endif - default: return MTLPixelFormatInvalid; - } -} - -_SOKOL_PRIVATE MTLColorWriteMask _sg_mtl_color_write_mask(sg_color_mask m) { - MTLColorWriteMask mtl_mask = MTLColorWriteMaskNone; - if (m & SG_COLORMASK_R) { - mtl_mask |= MTLColorWriteMaskRed; - } - if (m & SG_COLORMASK_G) { - mtl_mask |= MTLColorWriteMaskGreen; - } - if (m & SG_COLORMASK_B) { - mtl_mask |= MTLColorWriteMaskBlue; - } - if (m & SG_COLORMASK_A) { - mtl_mask |= MTLColorWriteMaskAlpha; - } - return mtl_mask; -} - -_SOKOL_PRIVATE MTLBlendOperation _sg_mtl_blend_op(sg_blend_op op) { - switch (op) { - case SG_BLENDOP_ADD: return MTLBlendOperationAdd; - case SG_BLENDOP_SUBTRACT: return MTLBlendOperationSubtract; - case SG_BLENDOP_REVERSE_SUBTRACT: return MTLBlendOperationReverseSubtract; - default: SOKOL_UNREACHABLE; return (MTLBlendOperation)0; - } -} - -_SOKOL_PRIVATE MTLBlendFactor _sg_mtl_blend_factor(sg_blend_factor f) { - switch (f) { - case SG_BLENDFACTOR_ZERO: return MTLBlendFactorZero; - case SG_BLENDFACTOR_ONE: return MTLBlendFactorOne; - case SG_BLENDFACTOR_SRC_COLOR: return MTLBlendFactorSourceColor; - case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return MTLBlendFactorOneMinusSourceColor; - case SG_BLENDFACTOR_SRC_ALPHA: return MTLBlendFactorSourceAlpha; - case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return MTLBlendFactorOneMinusSourceAlpha; - case SG_BLENDFACTOR_DST_COLOR: return MTLBlendFactorDestinationColor; - case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return MTLBlendFactorOneMinusDestinationColor; - case SG_BLENDFACTOR_DST_ALPHA: return MTLBlendFactorDestinationAlpha; - case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return MTLBlendFactorOneMinusDestinationAlpha; - case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return MTLBlendFactorSourceAlphaSaturated; - case SG_BLENDFACTOR_BLEND_COLOR: return MTLBlendFactorBlendColor; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return MTLBlendFactorOneMinusBlendColor; - case SG_BLENDFACTOR_BLEND_ALPHA: return MTLBlendFactorBlendAlpha; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return MTLBlendFactorOneMinusBlendAlpha; - default: SOKOL_UNREACHABLE; return (MTLBlendFactor)0; - } -} - -_SOKOL_PRIVATE MTLCompareFunction _sg_mtl_compare_func(sg_compare_func f) { - switch (f) { - case SG_COMPAREFUNC_NEVER: return MTLCompareFunctionNever; - case SG_COMPAREFUNC_LESS: return MTLCompareFunctionLess; - case SG_COMPAREFUNC_EQUAL: return MTLCompareFunctionEqual; - case SG_COMPAREFUNC_LESS_EQUAL: return MTLCompareFunctionLessEqual; - case SG_COMPAREFUNC_GREATER: return MTLCompareFunctionGreater; - case SG_COMPAREFUNC_NOT_EQUAL: return MTLCompareFunctionNotEqual; - case SG_COMPAREFUNC_GREATER_EQUAL: return MTLCompareFunctionGreaterEqual; - case SG_COMPAREFUNC_ALWAYS: return MTLCompareFunctionAlways; - default: SOKOL_UNREACHABLE; return (MTLCompareFunction)0; - } -} - -_SOKOL_PRIVATE MTLStencilOperation _sg_mtl_stencil_op(sg_stencil_op op) { - switch (op) { - case SG_STENCILOP_KEEP: return MTLStencilOperationKeep; - case SG_STENCILOP_ZERO: return MTLStencilOperationZero; - case SG_STENCILOP_REPLACE: return MTLStencilOperationReplace; - case SG_STENCILOP_INCR_CLAMP: return MTLStencilOperationIncrementClamp; - case SG_STENCILOP_DECR_CLAMP: return MTLStencilOperationDecrementClamp; - case SG_STENCILOP_INVERT: return MTLStencilOperationInvert; - case SG_STENCILOP_INCR_WRAP: return MTLStencilOperationIncrementWrap; - case SG_STENCILOP_DECR_WRAP: return MTLStencilOperationDecrementWrap; - default: SOKOL_UNREACHABLE; return (MTLStencilOperation)0; - } -} - -_SOKOL_PRIVATE MTLCullMode _sg_mtl_cull_mode(sg_cull_mode m) { - switch (m) { - case SG_CULLMODE_NONE: return MTLCullModeNone; - case SG_CULLMODE_FRONT: return MTLCullModeFront; - case SG_CULLMODE_BACK: return MTLCullModeBack; - default: SOKOL_UNREACHABLE; return (MTLCullMode)0; - } -} - -_SOKOL_PRIVATE MTLWinding _sg_mtl_winding(sg_face_winding w) { - switch (w) { - case SG_FACEWINDING_CW: return MTLWindingClockwise; - case SG_FACEWINDING_CCW: return MTLWindingCounterClockwise; - default: SOKOL_UNREACHABLE; return (MTLWinding)0; - } -} - -_SOKOL_PRIVATE MTLIndexType _sg_mtl_index_type(sg_index_type t) { - switch (t) { - case SG_INDEXTYPE_UINT16: return MTLIndexTypeUInt16; - case SG_INDEXTYPE_UINT32: return MTLIndexTypeUInt32; - default: SOKOL_UNREACHABLE; return (MTLIndexType)0; - } -} - -_SOKOL_PRIVATE int _sg_mtl_index_size(sg_index_type t) { - switch (t) { - case SG_INDEXTYPE_NONE: return 0; - case SG_INDEXTYPE_UINT16: return 2; - case SG_INDEXTYPE_UINT32: return 4; - default: SOKOL_UNREACHABLE; return 0; - } -} - -_SOKOL_PRIVATE MTLTextureType _sg_mtl_texture_type(sg_image_type t) { - switch (t) { - case SG_IMAGETYPE_2D: return MTLTextureType2D; - case SG_IMAGETYPE_CUBE: return MTLTextureTypeCube; - case SG_IMAGETYPE_3D: return MTLTextureType3D; - case SG_IMAGETYPE_ARRAY: return MTLTextureType2DArray; - default: SOKOL_UNREACHABLE; return (MTLTextureType)0; - } -} - -_SOKOL_PRIVATE bool _sg_mtl_is_pvrtc(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: - return true; - default: - return false; - } -} - -_SOKOL_PRIVATE MTLSamplerAddressMode _sg_mtl_address_mode(sg_wrap w) { - if (_sg.features.image_clamp_to_border) { - if (@available(macOS 12.0, iOS 14.0, *)) { - // border color feature available - switch (w) { - case SG_WRAP_REPEAT: return MTLSamplerAddressModeRepeat; - case SG_WRAP_CLAMP_TO_EDGE: return MTLSamplerAddressModeClampToEdge; - case SG_WRAP_CLAMP_TO_BORDER: return MTLSamplerAddressModeClampToBorderColor; - case SG_WRAP_MIRRORED_REPEAT: return MTLSamplerAddressModeMirrorRepeat; - default: SOKOL_UNREACHABLE; return (MTLSamplerAddressMode)0; - } - } - } - // fallthrough: clamp to border no supported - switch (w) { - case SG_WRAP_REPEAT: return MTLSamplerAddressModeRepeat; - case SG_WRAP_CLAMP_TO_EDGE: return MTLSamplerAddressModeClampToEdge; - case SG_WRAP_CLAMP_TO_BORDER: return MTLSamplerAddressModeClampToEdge; - case SG_WRAP_MIRRORED_REPEAT: return MTLSamplerAddressModeMirrorRepeat; - default: SOKOL_UNREACHABLE; return (MTLSamplerAddressMode)0; - } -} - -_SOKOL_PRIVATE API_AVAILABLE(ios(14.0), macos(12.0)) MTLSamplerBorderColor _sg_mtl_border_color(sg_border_color c) { - switch (c) { - case SG_BORDERCOLOR_TRANSPARENT_BLACK: return MTLSamplerBorderColorTransparentBlack; - case SG_BORDERCOLOR_OPAQUE_BLACK: return MTLSamplerBorderColorOpaqueBlack; - case SG_BORDERCOLOR_OPAQUE_WHITE: return MTLSamplerBorderColorOpaqueWhite; - default: SOKOL_UNREACHABLE; return (MTLSamplerBorderColor)0; - } -} - -_SOKOL_PRIVATE MTLSamplerMinMagFilter _sg_mtl_minmag_filter(sg_filter f) { - switch (f) { - case SG_FILTER_NEAREST: - return MTLSamplerMinMagFilterNearest; - case SG_FILTER_LINEAR: - return MTLSamplerMinMagFilterLinear; - default: - SOKOL_UNREACHABLE; return (MTLSamplerMinMagFilter)0; - } -} - -_SOKOL_PRIVATE MTLSamplerMipFilter _sg_mtl_mipmap_filter(sg_filter f) { - switch (f) { - case SG_FILTER_NEAREST: - return MTLSamplerMipFilterNearest; - case SG_FILTER_LINEAR: - return MTLSamplerMipFilterLinear; - default: - SOKOL_UNREACHABLE; return (MTLSamplerMipFilter)0; - } -} - -//-- a pool for all Metal resource objects, with deferred release queue --------- -_SOKOL_PRIVATE void _sg_mtl_init_pool(const sg_desc* desc) { - _sg.mtl.idpool.num_slots = 2 * - ( - 2 * desc->buffer_pool_size + - 4 * desc->image_pool_size + - 1 * desc->sampler_pool_size + - 4 * desc->shader_pool_size + - 2 * desc->pipeline_pool_size + - desc->attachments_pool_size + - 128 - ); - _sg.mtl.idpool.pool = [NSMutableArray arrayWithCapacity:(NSUInteger)_sg.mtl.idpool.num_slots]; - _SG_OBJC_RETAIN(_sg.mtl.idpool.pool); - NSNull* null = [NSNull null]; - for (int i = 0; i < _sg.mtl.idpool.num_slots; i++) { - [_sg.mtl.idpool.pool addObject:null]; - } - SOKOL_ASSERT([_sg.mtl.idpool.pool count] == (NSUInteger)_sg.mtl.idpool.num_slots); - // a queue of currently free slot indices - _sg.mtl.idpool.free_queue_top = 0; - _sg.mtl.idpool.free_queue = (int*)_sg_malloc_clear((size_t)_sg.mtl.idpool.num_slots * sizeof(int)); - // pool slot 0 is reserved! - for (int i = _sg.mtl.idpool.num_slots-1; i >= 1; i--) { - _sg.mtl.idpool.free_queue[_sg.mtl.idpool.free_queue_top++] = i; - } - // a circular queue which holds release items (frame index when a resource is to be released, and the resource's pool index - _sg.mtl.idpool.release_queue_front = 0; - _sg.mtl.idpool.release_queue_back = 0; - _sg.mtl.idpool.release_queue = (_sg_mtl_release_item_t*)_sg_malloc_clear((size_t)_sg.mtl.idpool.num_slots * sizeof(_sg_mtl_release_item_t)); - for (int i = 0; i < _sg.mtl.idpool.num_slots; i++) { - _sg.mtl.idpool.release_queue[i].frame_index = 0; - _sg.mtl.idpool.release_queue[i].slot_index = _SG_MTL_INVALID_SLOT_INDEX; - } -} - -_SOKOL_PRIVATE void _sg_mtl_destroy_pool(void) { - _sg_free(_sg.mtl.idpool.release_queue); _sg.mtl.idpool.release_queue = 0; - _sg_free(_sg.mtl.idpool.free_queue); _sg.mtl.idpool.free_queue = 0; - _SG_OBJC_RELEASE(_sg.mtl.idpool.pool); -} - -// get a new free resource pool slot -_SOKOL_PRIVATE int _sg_mtl_alloc_pool_slot(void) { - SOKOL_ASSERT(_sg.mtl.idpool.free_queue_top > 0); - const int slot_index = _sg.mtl.idpool.free_queue[--_sg.mtl.idpool.free_queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); - return slot_index; -} - -// put a free resource pool slot back into the free-queue -_SOKOL_PRIVATE void _sg_mtl_free_pool_slot(int slot_index) { - SOKOL_ASSERT(_sg.mtl.idpool.free_queue_top < _sg.mtl.idpool.num_slots); - SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); - _sg.mtl.idpool.free_queue[_sg.mtl.idpool.free_queue_top++] = slot_index; -} - -// add an MTLResource to the pool, return pool index or 0 if input was 'nil' -_SOKOL_PRIVATE int _sg_mtl_add_resource(id res) { - if (nil == res) { - return _SG_MTL_INVALID_SLOT_INDEX; - } - _sg_stats_add(metal.idpool.num_added, 1); - const int slot_index = _sg_mtl_alloc_pool_slot(); - // NOTE: the NSMutableArray will take ownership of its items - SOKOL_ASSERT([NSNull null] == _sg.mtl.idpool.pool[(NSUInteger)slot_index]); - _sg.mtl.idpool.pool[(NSUInteger)slot_index] = res; - return slot_index; -} - -/* mark an MTLResource for release, this will put the resource into the - deferred-release queue, and the resource will then be released N frames later, - the special pool index 0 will be ignored (this means that a nil - value was provided to _sg_mtl_add_resource() -*/ -_SOKOL_PRIVATE void _sg_mtl_release_resource(uint32_t frame_index, int slot_index) { - if (slot_index == _SG_MTL_INVALID_SLOT_INDEX) { - return; - } - _sg_stats_add(metal.idpool.num_released, 1); - SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); - SOKOL_ASSERT([NSNull null] != _sg.mtl.idpool.pool[(NSUInteger)slot_index]); - int release_index = _sg.mtl.idpool.release_queue_front++; - if (_sg.mtl.idpool.release_queue_front >= _sg.mtl.idpool.num_slots) { - // wrap-around - _sg.mtl.idpool.release_queue_front = 0; - } - // release queue full? - SOKOL_ASSERT(_sg.mtl.idpool.release_queue_front != _sg.mtl.idpool.release_queue_back); - SOKOL_ASSERT(0 == _sg.mtl.idpool.release_queue[release_index].frame_index); - const uint32_t safe_to_release_frame_index = frame_index + SG_NUM_INFLIGHT_FRAMES + 1; - _sg.mtl.idpool.release_queue[release_index].frame_index = safe_to_release_frame_index; - _sg.mtl.idpool.release_queue[release_index].slot_index = slot_index; -} - -// run garbage-collection pass on all resources in the release-queue -_SOKOL_PRIVATE void _sg_mtl_garbage_collect(uint32_t frame_index) { - while (_sg.mtl.idpool.release_queue_back != _sg.mtl.idpool.release_queue_front) { - if (frame_index < _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].frame_index) { - // don't need to check further, release-items past this are too young - break; - } - _sg_stats_add(metal.idpool.num_garbage_collected, 1); - // safe to release this resource - const int slot_index = _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].slot_index; - SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); - // note: the NSMutableArray takes ownership of its items, assigning an NSNull object will - // release the object, no matter if using ARC or not - SOKOL_ASSERT(_sg.mtl.idpool.pool[(NSUInteger)slot_index] != [NSNull null]); - _sg.mtl.idpool.pool[(NSUInteger)slot_index] = [NSNull null]; - // put the now free pool index back on the free queue - _sg_mtl_free_pool_slot(slot_index); - // reset the release queue slot and advance the back index - _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].frame_index = 0; - _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].slot_index = _SG_MTL_INVALID_SLOT_INDEX; - _sg.mtl.idpool.release_queue_back++; - if (_sg.mtl.idpool.release_queue_back >= _sg.mtl.idpool.num_slots) { - // wrap-around - _sg.mtl.idpool.release_queue_back = 0; - } - } -} - -_SOKOL_PRIVATE id _sg_mtl_id(int slot_index) { - return _sg.mtl.idpool.pool[(NSUInteger)slot_index]; -} - -_SOKOL_PRIVATE void _sg_mtl_clear_state_cache(void) { - _sg_clear(&_sg.mtl.state_cache, sizeof(_sg.mtl.state_cache)); -} - -// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf -_SOKOL_PRIVATE void _sg_mtl_init_caps(void) { - #if defined(_SG_TARGET_MACOS) - _sg.backend = SG_BACKEND_METAL_MACOS; - #elif defined(_SG_TARGET_IOS) - #if defined(_SG_TARGET_IOS_SIMULATOR) - _sg.backend = SG_BACKEND_METAL_SIMULATOR; - #else - _sg.backend = SG_BACKEND_METAL_IOS; - #endif - #endif - _sg.features.origin_top_left = true; - _sg.features.mrt_independent_blend_state = true; - _sg.features.mrt_independent_write_mask = true; - _sg.features.storage_buffer = true; - - _sg.features.image_clamp_to_border = false; - #if (MAC_OS_X_VERSION_MAX_ALLOWED >= 120000) || (__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000) - if (@available(macOS 12.0, iOS 14.0, *)) { - _sg.features.image_clamp_to_border = [_sg.mtl.device supportsFamily:MTLGPUFamilyApple7] - || [_sg.mtl.device supportsFamily:MTLGPUFamilyMac2]; - #if (MAC_OS_X_VERSION_MAX_ALLOWED >= 130000) || (__IPHONE_OS_VERSION_MAX_ALLOWED >= 160000) - if (!_sg.features.image_clamp_to_border) { - if (@available(macOS 13.0, iOS 16.0, *)) { - _sg.features.image_clamp_to_border = [_sg.mtl.device supportsFamily:MTLGPUFamilyMetal3]; - } - } - #endif - } - #endif - - #if defined(_SG_TARGET_MACOS) - _sg.limits.max_image_size_2d = 16 * 1024; - _sg.limits.max_image_size_cube = 16 * 1024; - _sg.limits.max_image_size_3d = 2 * 1024; - _sg.limits.max_image_size_array = 16 * 1024; - _sg.limits.max_image_array_layers = 2 * 1024; - #else - // FIXME: newer iOS devices support 16k textures - _sg.limits.max_image_size_2d = 8 * 1024; - _sg.limits.max_image_size_cube = 8 * 1024; - _sg.limits.max_image_size_3d = 2 * 1024; - _sg.limits.max_image_size_array = 8 * 1024; - _sg.limits.max_image_array_layers = 2 * 1024; - #endif - _sg.limits.max_vertex_attrs = SG_MAX_VERTEX_ATTRIBUTES; - - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8SN]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8SI]); - #if defined(_SG_TARGET_MACOS) - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16SN]); - #else - _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_R16]); - _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_R16SN]); - #endif - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16SI]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16F]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8SN]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32SI]); - #if defined(_SG_TARGET_MACOS) - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R32F]); - #else - _sg_pixelformat_sbr(&_sg.formats[SG_PIXELFORMAT_R32F]); - #endif - #if defined(_SG_TARGET_MACOS) - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16SN]); - #else - _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_RG16]); - _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_RG16SN]); - #endif - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16SI]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16F]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_SRGB8A8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8SN]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8SI]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_BGRA8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGB10A2]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG11B10F]); - #if defined(_SG_TARGET_MACOS) - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGB9E5]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32SI]); - #else - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGB9E5]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32SI]); - #endif - #if defined(_SG_TARGET_MACOS) - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG32F]); - #else - _sg_pixelformat_sbr(&_sg.formats[SG_PIXELFORMAT_RG32F]); - #endif - #if defined(_SG_TARGET_MACOS) - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16SN]); - #else - _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_RGBA16]); - _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_RGBA16SN]); - #endif - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16SI]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); - #if defined(_SG_TARGET_MACOS) - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); - _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); - #else - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); - #endif - _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH]); - _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL]); - #if defined(_SG_TARGET_MACOS) - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC1_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC2_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_SRGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_R]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_RSN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RG]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RGSN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBF]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBUF]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_SRGBA]); - #else - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_2BPP]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_4BPP]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_2BPP]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_4BPP]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8A8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11SN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11SN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_SRGBA]); - - #endif -} - -//-- main Metal backend state and functions ------------------------------------ -_SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { - // assume already zero-initialized - SOKOL_ASSERT(desc); - SOKOL_ASSERT(desc->environment.metal.device); - SOKOL_ASSERT(desc->uniform_buffer_size > 0); - _sg_mtl_init_pool(desc); - _sg_mtl_clear_state_cache(); - _sg.mtl.valid = true; - _sg.mtl.ub_size = desc->uniform_buffer_size; - _sg.mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); - _sg.mtl.device = (__bridge id) desc->environment.metal.device; - _sg.mtl.cmd_queue = [_sg.mtl.device newCommandQueue]; - - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - _sg.mtl.uniform_buffers[i] = [_sg.mtl.device - newBufferWithLength:(NSUInteger)_sg.mtl.ub_size - options:MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared - ]; - #if defined(SOKOL_DEBUG) - _sg.mtl.uniform_buffers[i].label = [NSString stringWithFormat:@"sg-uniform-buffer.%d", i]; - #endif - } - - if (desc->mtl_force_managed_storage_mode) { - _sg.mtl.use_shared_storage_mode = false; - } else if (@available(macOS 10.15, iOS 13.0, *)) { - // on Intel Macs, always use managed resources even though the - // device says it supports unified memory (because of texture restrictions) - const bool is_apple_gpu = [_sg.mtl.device supportsFamily:MTLGPUFamilyApple1]; - if (!is_apple_gpu) { - _sg.mtl.use_shared_storage_mode = false; - } else { - _sg.mtl.use_shared_storage_mode = true; - } - } else { - #if defined(_SG_TARGET_MACOS) - _sg.mtl.use_shared_storage_mode = false; - #else - _sg.mtl.use_shared_storage_mode = true; - #endif - } - _sg_mtl_init_caps(); -} - -_SOKOL_PRIVATE void _sg_mtl_discard_backend(void) { - SOKOL_ASSERT(_sg.mtl.valid); - // wait for the last frame to finish - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - dispatch_semaphore_wait(_sg.mtl.sem, DISPATCH_TIME_FOREVER); - } - // semaphore must be "relinquished" before destruction - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - dispatch_semaphore_signal(_sg.mtl.sem); - } - _sg_mtl_garbage_collect(_sg.frame_index + SG_NUM_INFLIGHT_FRAMES + 2); - _sg_mtl_destroy_pool(); - _sg.mtl.valid = false; - - _SG_OBJC_RELEASE(_sg.mtl.sem); - _SG_OBJC_RELEASE(_sg.mtl.device); - _SG_OBJC_RELEASE(_sg.mtl.cmd_queue); - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - _SG_OBJC_RELEASE(_sg.mtl.uniform_buffers[i]); - } - // NOTE: MTLCommandBuffer and MTLRenderCommandEncoder are auto-released - _sg.mtl.cmd_buffer = nil; - _sg.mtl.cmd_encoder = nil; -} - -_SOKOL_PRIVATE void _sg_mtl_bind_uniform_buffers(void) { - SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); - for (int slot = 0; slot < SG_MAX_SHADERSTAGE_UBS; slot++) { - [_sg.mtl.cmd_encoder - setVertexBuffer:_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] - offset:0 - atIndex:(NSUInteger)slot]; - [_sg.mtl.cmd_encoder - setFragmentBuffer:_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] - offset:0 - atIndex:(NSUInteger)slot]; - } -} - -_SOKOL_PRIVATE void _sg_mtl_reset_state_cache(void) { - _sg_mtl_clear_state_cache(); - // need to restore the uniform buffer binding (normally happens in _sg_mtl_begin_pass() - if (nil != _sg.mtl.cmd_encoder) { - _sg_mtl_bind_uniform_buffers(); - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { - SOKOL_ASSERT(buf && desc); - const bool injected = (0 != desc->mtl_buffers[0]); - MTLResourceOptions mtl_options = _sg_mtl_buffer_resource_options(buf->cmn.usage); - for (int slot = 0; slot < buf->cmn.num_slots; slot++) { - id mtl_buf; - if (injected) { - SOKOL_ASSERT(desc->mtl_buffers[slot]); - mtl_buf = (__bridge id) desc->mtl_buffers[slot]; - } else { - if (buf->cmn.usage == SG_USAGE_IMMUTABLE) { - SOKOL_ASSERT(desc->data.ptr); - mtl_buf = [_sg.mtl.device newBufferWithBytes:desc->data.ptr length:(NSUInteger)buf->cmn.size options:mtl_options]; - } else { - mtl_buf = [_sg.mtl.device newBufferWithLength:(NSUInteger)buf->cmn.size options:mtl_options]; - } - if (nil == mtl_buf) { - _SG_ERROR(METAL_CREATE_BUFFER_FAILED); - return SG_RESOURCESTATE_FAILED; - } - } - #if defined(SOKOL_DEBUG) - if (desc->label) { - mtl_buf.label = [NSString stringWithFormat:@"%s.%d", desc->label, slot]; - } - #endif - buf->mtl.buf[slot] = _sg_mtl_add_resource(mtl_buf); - _SG_OBJC_RELEASE(mtl_buf); - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_mtl_discard_buffer(_sg_buffer_t* buf) { - SOKOL_ASSERT(buf); - for (int slot = 0; slot < buf->cmn.num_slots; slot++) { - // it's valid to call release resource with '0' - _sg_mtl_release_resource(_sg.frame_index, buf->mtl.buf[slot]); - } -} - -_SOKOL_PRIVATE void _sg_mtl_copy_image_data(const _sg_image_t* img, __unsafe_unretained id mtl_tex, const sg_image_data* data) { - const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; - const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices : 1; - for (int face_index = 0; face_index < num_faces; face_index++) { - for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++) { - SOKOL_ASSERT(data->subimage[face_index][mip_index].ptr); - SOKOL_ASSERT(data->subimage[face_index][mip_index].size > 0); - const uint8_t* data_ptr = (const uint8_t*)data->subimage[face_index][mip_index].ptr; - const int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); - const int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); - // special case PVRTC formats: bytePerRow and bytesPerImage must be 0 - int bytes_per_row = 0; - int bytes_per_slice = 0; - if (!_sg_mtl_is_pvrtc(img->cmn.pixel_format)) { - bytes_per_row = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); - bytes_per_slice = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1); - } - /* bytesPerImage special case: https://developer.apple.com/documentation/metal/mtltexture/1515679-replaceregion - - "Supply a nonzero value only when you copy data to a MTLTextureType3D type texture" - */ - MTLRegion region; - int bytes_per_image; - if (img->cmn.type == SG_IMAGETYPE_3D) { - const int mip_depth = _sg_miplevel_dim(img->cmn.num_slices, mip_index); - region = MTLRegionMake3D(0, 0, 0, (NSUInteger)mip_width, (NSUInteger)mip_height, (NSUInteger)mip_depth); - bytes_per_image = bytes_per_slice; - // FIXME: apparently the minimal bytes_per_image size for 3D texture is 4 KByte... somehow need to handle this - } else { - region = MTLRegionMake2D(0, 0, (NSUInteger)mip_width, (NSUInteger)mip_height); - bytes_per_image = 0; - } - - for (int slice_index = 0; slice_index < num_slices; slice_index++) { - const int mtl_slice_index = (img->cmn.type == SG_IMAGETYPE_CUBE) ? face_index : slice_index; - const int slice_offset = slice_index * bytes_per_slice; - SOKOL_ASSERT((slice_offset + bytes_per_slice) <= (int)data->subimage[face_index][mip_index].size); - [mtl_tex replaceRegion:region - mipmapLevel:(NSUInteger)mip_index - slice:(NSUInteger)mtl_slice_index - withBytes:data_ptr + slice_offset - bytesPerRow:(NSUInteger)bytes_per_row - bytesPerImage:(NSUInteger)bytes_per_image]; - } - } - } -} - -// initialize MTLTextureDescriptor with common attributes -_SOKOL_PRIVATE bool _sg_mtl_init_texdesc_common(MTLTextureDescriptor* mtl_desc, _sg_image_t* img) { - mtl_desc.textureType = _sg_mtl_texture_type(img->cmn.type); - mtl_desc.pixelFormat = _sg_mtl_pixel_format(img->cmn.pixel_format); - if (MTLPixelFormatInvalid == mtl_desc.pixelFormat) { - _SG_ERROR(METAL_TEXTURE_FORMAT_NOT_SUPPORTED); - return false; - } - mtl_desc.width = (NSUInteger)img->cmn.width; - mtl_desc.height = (NSUInteger)img->cmn.height; - if (SG_IMAGETYPE_3D == img->cmn.type) { - mtl_desc.depth = (NSUInteger)img->cmn.num_slices; - } else { - mtl_desc.depth = 1; - } - mtl_desc.mipmapLevelCount = (NSUInteger)img->cmn.num_mipmaps; - if (SG_IMAGETYPE_ARRAY == img->cmn.type) { - mtl_desc.arrayLength = (NSUInteger)img->cmn.num_slices; - } else { - mtl_desc.arrayLength = 1; - } - mtl_desc.usage = MTLTextureUsageShaderRead; - MTLResourceOptions res_options = 0; - if (img->cmn.usage != SG_USAGE_IMMUTABLE) { - res_options |= MTLResourceCPUCacheModeWriteCombined; - } - res_options |= _sg_mtl_resource_options_storage_mode_managed_or_shared(); - mtl_desc.resourceOptions = res_options; - return true; -} - -// initialize MTLTextureDescriptor with rendertarget attributes -_SOKOL_PRIVATE void _sg_mtl_init_texdesc_rt(MTLTextureDescriptor* mtl_desc, _sg_image_t* img) { - SOKOL_ASSERT(img->cmn.render_target); - _SOKOL_UNUSED(img); - mtl_desc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget; - mtl_desc.resourceOptions = MTLResourceStorageModePrivate; -} - -// initialize MTLTextureDescriptor with MSAA attributes -_SOKOL_PRIVATE void _sg_mtl_init_texdesc_rt_msaa(MTLTextureDescriptor* mtl_desc, _sg_image_t* img) { - SOKOL_ASSERT(img->cmn.sample_count > 1); - mtl_desc.usage = MTLTextureUsageRenderTarget; - mtl_desc.resourceOptions = MTLResourceStorageModePrivate; - mtl_desc.textureType = MTLTextureType2DMultisample; - mtl_desc.sampleCount = (NSUInteger)img->cmn.sample_count; -} - -_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_image(_sg_image_t* img, const sg_image_desc* desc) { - SOKOL_ASSERT(img && desc); - const bool injected = (0 != desc->mtl_textures[0]); - - // first initialize all Metal resource pool slots to 'empty' - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - img->mtl.tex[i] = _sg_mtl_add_resource(nil); - } - - // initialize a Metal texture descriptor - MTLTextureDescriptor* mtl_desc = [[MTLTextureDescriptor alloc] init]; - if (!_sg_mtl_init_texdesc_common(mtl_desc, img)) { - _SG_OBJC_RELEASE(mtl_desc); - return SG_RESOURCESTATE_FAILED; - } - if (img->cmn.render_target) { - if (img->cmn.sample_count > 1) { - _sg_mtl_init_texdesc_rt_msaa(mtl_desc, img); - } else { - _sg_mtl_init_texdesc_rt(mtl_desc, img); - } - } - for (int slot = 0; slot < img->cmn.num_slots; slot++) { - id mtl_tex; - if (injected) { - SOKOL_ASSERT(desc->mtl_textures[slot]); - mtl_tex = (__bridge id) desc->mtl_textures[slot]; - } else { - mtl_tex = [_sg.mtl.device newTextureWithDescriptor:mtl_desc]; - if (nil == mtl_tex) { - _SG_OBJC_RELEASE(mtl_desc); - _SG_ERROR(METAL_CREATE_TEXTURE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - if ((img->cmn.usage == SG_USAGE_IMMUTABLE) && !img->cmn.render_target) { - _sg_mtl_copy_image_data(img, mtl_tex, &desc->data); - } - } - #if defined(SOKOL_DEBUG) - if (desc->label) { - mtl_tex.label = [NSString stringWithFormat:@"%s.%d", desc->label, slot]; - } - #endif - img->mtl.tex[slot] = _sg_mtl_add_resource(mtl_tex); - _SG_OBJC_RELEASE(mtl_tex); - } - _SG_OBJC_RELEASE(mtl_desc); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_mtl_discard_image(_sg_image_t* img) { - SOKOL_ASSERT(img); - // it's valid to call release resource with a 'null resource' - for (int slot = 0; slot < img->cmn.num_slots; slot++) { - _sg_mtl_release_resource(_sg.frame_index, img->mtl.tex[slot]); - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_sampler(_sg_sampler_t* smp, const sg_sampler_desc* desc) { - SOKOL_ASSERT(smp && desc); - id mtl_smp; - const bool injected = (0 != desc->mtl_sampler); - if (injected) { - SOKOL_ASSERT(desc->mtl_sampler); - mtl_smp = (__bridge id) desc->mtl_sampler; - } else { - MTLSamplerDescriptor* mtl_desc = [[MTLSamplerDescriptor alloc] init]; - mtl_desc.sAddressMode = _sg_mtl_address_mode(desc->wrap_u); - mtl_desc.tAddressMode = _sg_mtl_address_mode(desc->wrap_v); - mtl_desc.rAddressMode = _sg_mtl_address_mode(desc->wrap_w); - if (_sg.features.image_clamp_to_border) { - if (@available(macOS 12.0, iOS 14.0, *)) { - mtl_desc.borderColor = _sg_mtl_border_color(desc->border_color); - } - } - mtl_desc.minFilter = _sg_mtl_minmag_filter(desc->min_filter); - mtl_desc.magFilter = _sg_mtl_minmag_filter(desc->mag_filter); - mtl_desc.mipFilter = _sg_mtl_mipmap_filter(desc->mipmap_filter); - mtl_desc.lodMinClamp = desc->min_lod; - mtl_desc.lodMaxClamp = desc->max_lod; - // FIXME: lodAverage? - mtl_desc.maxAnisotropy = desc->max_anisotropy; - mtl_desc.normalizedCoordinates = YES; - mtl_desc.compareFunction = _sg_mtl_compare_func(desc->compare); - #if defined(SOKOL_DEBUG) - if (desc->label) { - mtl_desc.label = [NSString stringWithUTF8String:desc->label]; - } - #endif - mtl_smp = [_sg.mtl.device newSamplerStateWithDescriptor:mtl_desc]; - _SG_OBJC_RELEASE(mtl_desc); - if (nil == mtl_smp) { - _SG_ERROR(METAL_CREATE_SAMPLER_FAILED); - return SG_RESOURCESTATE_FAILED; - } - } - smp->mtl.sampler_state = _sg_mtl_add_resource(mtl_smp); - _SG_OBJC_RELEASE(mtl_smp); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_mtl_discard_sampler(_sg_sampler_t* smp) { - SOKOL_ASSERT(smp); - // it's valid to call release resource with a 'null resource' - _sg_mtl_release_resource(_sg.frame_index, smp->mtl.sampler_state); -} - -_SOKOL_PRIVATE id _sg_mtl_compile_library(const char* src) { - NSError* err = NULL; - id lib = [_sg.mtl.device - newLibraryWithSource:[NSString stringWithUTF8String:src] - options:nil - error:&err - ]; - if (err) { - _SG_ERROR(METAL_SHADER_COMPILATION_FAILED); - _SG_LOGMSG(METAL_SHADER_COMPILATION_OUTPUT, [err.localizedDescription UTF8String]); - } - return lib; -} - -_SOKOL_PRIVATE id _sg_mtl_library_from_bytecode(const void* ptr, size_t num_bytes) { - NSError* err = NULL; - dispatch_data_t lib_data = dispatch_data_create(ptr, num_bytes, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT); - id lib = [_sg.mtl.device newLibraryWithData:lib_data error:&err]; - if (err) { - _SG_ERROR(METAL_SHADER_CREATION_FAILED); - _SG_LOGMSG(METAL_SHADER_COMPILATION_OUTPUT, [err.localizedDescription UTF8String]); - } - _SG_OBJC_RELEASE(lib_data); - return lib; -} - -_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { - SOKOL_ASSERT(shd && desc); - - // create metal library objects and lookup entry functions - id vs_lib = nil; - id fs_lib = nil; - id vs_func = nil; - id fs_func = nil; - const char* vs_entry = desc->vs.entry; - const char* fs_entry = desc->fs.entry; - if (desc->vs.bytecode.ptr && desc->fs.bytecode.ptr) { - // separate byte code provided - vs_lib = _sg_mtl_library_from_bytecode(desc->vs.bytecode.ptr, desc->vs.bytecode.size); - fs_lib = _sg_mtl_library_from_bytecode(desc->fs.bytecode.ptr, desc->fs.bytecode.size); - if ((nil == vs_lib) || (nil == fs_lib)) { - goto failed; - } - vs_func = [vs_lib newFunctionWithName:[NSString stringWithUTF8String:vs_entry]]; - fs_func = [fs_lib newFunctionWithName:[NSString stringWithUTF8String:fs_entry]]; - } else if (desc->vs.source && desc->fs.source) { - // separate sources provided - vs_lib = _sg_mtl_compile_library(desc->vs.source); - fs_lib = _sg_mtl_compile_library(desc->fs.source); - if ((nil == vs_lib) || (nil == fs_lib)) { - goto failed; - } - vs_func = [vs_lib newFunctionWithName:[NSString stringWithUTF8String:vs_entry]]; - fs_func = [fs_lib newFunctionWithName:[NSString stringWithUTF8String:fs_entry]]; - } else { - goto failed; - } - if (nil == vs_func) { - _SG_ERROR(METAL_VERTEX_SHADER_ENTRY_NOT_FOUND); - goto failed; - } - if (nil == fs_func) { - _SG_ERROR(METAL_FRAGMENT_SHADER_ENTRY_NOT_FOUND); - goto failed; - } - #if defined(SOKOL_DEBUG) - if (desc->label) { - vs_lib.label = [NSString stringWithFormat:@"%s.vs", desc->label]; - fs_lib.label = [NSString stringWithFormat:@"%s.fs", desc->label]; - } - #endif - // it is legal to call _sg_mtl_add_resource with a nil value, this will return a special 0xFFFFFFFF index - shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_lib = _sg_mtl_add_resource(vs_lib); - _SG_OBJC_RELEASE(vs_lib); - shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_lib = _sg_mtl_add_resource(fs_lib); - _SG_OBJC_RELEASE(fs_lib); - shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func = _sg_mtl_add_resource(vs_func); - _SG_OBJC_RELEASE(vs_func); - shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func = _sg_mtl_add_resource(fs_func); - _SG_OBJC_RELEASE(fs_func); - return SG_RESOURCESTATE_VALID; -failed: - if (vs_lib != nil) { - _SG_OBJC_RELEASE(vs_lib); - } - if (fs_lib != nil) { - _SG_OBJC_RELEASE(fs_lib); - } - if (vs_func != nil) { - _SG_OBJC_RELEASE(vs_func); - } - if (fs_func != nil) { - _SG_OBJC_RELEASE(fs_func); - } - return SG_RESOURCESTATE_FAILED; -} - -_SOKOL_PRIVATE void _sg_mtl_discard_shader(_sg_shader_t* shd) { - SOKOL_ASSERT(shd); - // it is valid to call _sg_mtl_release_resource with a 'null resource' - _sg_mtl_release_resource(_sg.frame_index, shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func); - _sg_mtl_release_resource(_sg.frame_index, shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_lib); - _sg_mtl_release_resource(_sg.frame_index, shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func); - _sg_mtl_release_resource(_sg.frame_index, shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_lib); -} - -_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { - SOKOL_ASSERT(pip && shd && desc); - SOKOL_ASSERT(desc->shader.id == shd->slot.id); - - pip->shader = shd; - - sg_primitive_type prim_type = desc->primitive_type; - pip->mtl.prim_type = _sg_mtl_primitive_type(prim_type); - pip->mtl.index_size = _sg_mtl_index_size(pip->cmn.index_type); - if (SG_INDEXTYPE_NONE != pip->cmn.index_type) { - pip->mtl.index_type = _sg_mtl_index_type(pip->cmn.index_type); - } - pip->mtl.cull_mode = _sg_mtl_cull_mode(desc->cull_mode); - pip->mtl.winding = _sg_mtl_winding(desc->face_winding); - pip->mtl.stencil_ref = desc->stencil.ref; - - // create vertex-descriptor - MTLVertexDescriptor* vtx_desc = [MTLVertexDescriptor vertexDescriptor]; - for (NSUInteger attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { - const sg_vertex_attr_state* a_state = &desc->layout.attrs[attr_index]; - if (a_state->format == SG_VERTEXFORMAT_INVALID) { - break; - } - SOKOL_ASSERT(a_state->buffer_index < SG_MAX_VERTEX_BUFFERS); - vtx_desc.attributes[attr_index].format = _sg_mtl_vertex_format(a_state->format); - vtx_desc.attributes[attr_index].offset = (NSUInteger)a_state->offset; - vtx_desc.attributes[attr_index].bufferIndex = (NSUInteger)(a_state->buffer_index + SG_MAX_SHADERSTAGE_UBS); - pip->cmn.vertex_buffer_layout_active[a_state->buffer_index] = true; - } - for (NSUInteger layout_index = 0; layout_index < SG_MAX_VERTEX_BUFFERS; layout_index++) { - if (pip->cmn.vertex_buffer_layout_active[layout_index]) { - const sg_vertex_buffer_layout_state* l_state = &desc->layout.buffers[layout_index]; - const NSUInteger mtl_vb_slot = layout_index + SG_MAX_SHADERSTAGE_UBS; - SOKOL_ASSERT(l_state->stride > 0); - vtx_desc.layouts[mtl_vb_slot].stride = (NSUInteger)l_state->stride; - vtx_desc.layouts[mtl_vb_slot].stepFunction = _sg_mtl_step_function(l_state->step_func); - vtx_desc.layouts[mtl_vb_slot].stepRate = (NSUInteger)l_state->step_rate; - if (SG_VERTEXSTEP_PER_INSTANCE == l_state->step_func) { - // NOTE: not actually used in _sg_mtl_draw() - pip->cmn.use_instanced_draw = true; - } - } - } - - // render-pipeline descriptor - MTLRenderPipelineDescriptor* rp_desc = [[MTLRenderPipelineDescriptor alloc] init]; - rp_desc.vertexDescriptor = vtx_desc; - SOKOL_ASSERT(shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func != _SG_MTL_INVALID_SLOT_INDEX); - rp_desc.vertexFunction = _sg_mtl_id(shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func); - SOKOL_ASSERT(shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func != _SG_MTL_INVALID_SLOT_INDEX); - rp_desc.fragmentFunction = _sg_mtl_id(shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func); - rp_desc.rasterSampleCount = (NSUInteger)desc->sample_count; - rp_desc.alphaToCoverageEnabled = desc->alpha_to_coverage_enabled; - rp_desc.alphaToOneEnabled = NO; - rp_desc.rasterizationEnabled = YES; - rp_desc.depthAttachmentPixelFormat = _sg_mtl_pixel_format(desc->depth.pixel_format); - if (desc->depth.pixel_format == SG_PIXELFORMAT_DEPTH_STENCIL) { - rp_desc.stencilAttachmentPixelFormat = _sg_mtl_pixel_format(desc->depth.pixel_format); - } - if (@available(macOS 10.13, iOS 11.0, *)) { - for (NSUInteger i = 0; i < (SG_MAX_SHADERSTAGE_UBS+SG_MAX_VERTEX_BUFFERS); i++) { - rp_desc.vertexBuffers[i].mutability = MTLMutabilityImmutable; - } - for (NSUInteger i = 0; i < SG_MAX_SHADERSTAGE_UBS; i++) { - rp_desc.fragmentBuffers[i].mutability = MTLMutabilityImmutable; - } - } - for (NSUInteger i = 0; i < (NSUInteger)desc->color_count; i++) { - SOKOL_ASSERT(i < SG_MAX_COLOR_ATTACHMENTS); - const sg_color_target_state* cs = &desc->colors[i]; - rp_desc.colorAttachments[i].pixelFormat = _sg_mtl_pixel_format(cs->pixel_format); - rp_desc.colorAttachments[i].writeMask = _sg_mtl_color_write_mask(cs->write_mask); - rp_desc.colorAttachments[i].blendingEnabled = cs->blend.enabled; - rp_desc.colorAttachments[i].alphaBlendOperation = _sg_mtl_blend_op(cs->blend.op_alpha); - rp_desc.colorAttachments[i].rgbBlendOperation = _sg_mtl_blend_op(cs->blend.op_rgb); - rp_desc.colorAttachments[i].destinationAlphaBlendFactor = _sg_mtl_blend_factor(cs->blend.dst_factor_alpha); - rp_desc.colorAttachments[i].destinationRGBBlendFactor = _sg_mtl_blend_factor(cs->blend.dst_factor_rgb); - rp_desc.colorAttachments[i].sourceAlphaBlendFactor = _sg_mtl_blend_factor(cs->blend.src_factor_alpha); - rp_desc.colorAttachments[i].sourceRGBBlendFactor = _sg_mtl_blend_factor(cs->blend.src_factor_rgb); - } - #if defined(SOKOL_DEBUG) - if (desc->label) { - rp_desc.label = [NSString stringWithFormat:@"%s", desc->label]; - } - #endif - NSError* err = NULL; - id mtl_rps = [_sg.mtl.device newRenderPipelineStateWithDescriptor:rp_desc error:&err]; - _SG_OBJC_RELEASE(rp_desc); - if (nil == mtl_rps) { - SOKOL_ASSERT(err); - _SG_ERROR(METAL_CREATE_RPS_FAILED); - _SG_LOGMSG(METAL_CREATE_RPS_OUTPUT, [err.localizedDescription UTF8String]); - return SG_RESOURCESTATE_FAILED; - } - pip->mtl.rps = _sg_mtl_add_resource(mtl_rps); - _SG_OBJC_RELEASE(mtl_rps); - - // depth-stencil-state - MTLDepthStencilDescriptor* ds_desc = [[MTLDepthStencilDescriptor alloc] init]; - ds_desc.depthCompareFunction = _sg_mtl_compare_func(desc->depth.compare); - ds_desc.depthWriteEnabled = desc->depth.write_enabled; - if (desc->stencil.enabled) { - const sg_stencil_face_state* sb = &desc->stencil.back; - ds_desc.backFaceStencil = [[MTLStencilDescriptor alloc] init]; - ds_desc.backFaceStencil.stencilFailureOperation = _sg_mtl_stencil_op(sb->fail_op); - ds_desc.backFaceStencil.depthFailureOperation = _sg_mtl_stencil_op(sb->depth_fail_op); - ds_desc.backFaceStencil.depthStencilPassOperation = _sg_mtl_stencil_op(sb->pass_op); - ds_desc.backFaceStencil.stencilCompareFunction = _sg_mtl_compare_func(sb->compare); - ds_desc.backFaceStencil.readMask = desc->stencil.read_mask; - ds_desc.backFaceStencil.writeMask = desc->stencil.write_mask; - const sg_stencil_face_state* sf = &desc->stencil.front; - ds_desc.frontFaceStencil = [[MTLStencilDescriptor alloc] init]; - ds_desc.frontFaceStencil.stencilFailureOperation = _sg_mtl_stencil_op(sf->fail_op); - ds_desc.frontFaceStencil.depthFailureOperation = _sg_mtl_stencil_op(sf->depth_fail_op); - ds_desc.frontFaceStencil.depthStencilPassOperation = _sg_mtl_stencil_op(sf->pass_op); - ds_desc.frontFaceStencil.stencilCompareFunction = _sg_mtl_compare_func(sf->compare); - ds_desc.frontFaceStencil.readMask = desc->stencil.read_mask; - ds_desc.frontFaceStencil.writeMask = desc->stencil.write_mask; - } - #if defined(SOKOL_DEBUG) - if (desc->label) { - ds_desc.label = [NSString stringWithFormat:@"%s.dss", desc->label]; - } - #endif - id mtl_dss = [_sg.mtl.device newDepthStencilStateWithDescriptor:ds_desc]; - _SG_OBJC_RELEASE(ds_desc); - if (nil == mtl_dss) { - _SG_ERROR(METAL_CREATE_DSS_FAILED); - return SG_RESOURCESTATE_FAILED; - } - pip->mtl.dss = _sg_mtl_add_resource(mtl_dss); - _SG_OBJC_RELEASE(mtl_dss); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_mtl_discard_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - // it's valid to call release resource with a 'null resource' - _sg_mtl_release_resource(_sg.frame_index, pip->mtl.rps); - _sg_mtl_release_resource(_sg.frame_index, pip->mtl.dss); -} - -_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_attachments_desc* desc) { - SOKOL_ASSERT(atts && desc); - SOKOL_ASSERT(color_images && resolve_images); - - // copy image pointers - for (int i = 0; i < atts->cmn.num_colors; i++) { - const sg_attachment_desc* color_desc = &desc->colors[i]; - _SOKOL_UNUSED(color_desc); - SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == atts->mtl.colors[i].image); - SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); - atts->mtl.colors[i].image = color_images[i]; - - const sg_attachment_desc* resolve_desc = &desc->resolves[i]; - if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == atts->mtl.resolves[i].image); - SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); - SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); - atts->mtl.resolves[i].image = resolve_images[i]; - } - } - SOKOL_ASSERT(0 == atts->mtl.depth_stencil.image); - const sg_attachment_desc* ds_desc = &desc->depth_stencil; - if (ds_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(ds_img && (ds_img->slot.id == ds_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_img->cmn.pixel_format)); - atts->mtl.depth_stencil.image = ds_img; - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_mtl_discard_attachments(_sg_attachments_t* atts) { - SOKOL_ASSERT(atts); - _SOKOL_UNUSED(atts); -} - -_SOKOL_PRIVATE _sg_image_t* _sg_mtl_attachments_color_image(const _sg_attachments_t* atts, int index) { - // NOTE: may return null - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return atts->mtl.colors[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_mtl_attachments_resolve_image(const _sg_attachments_t* atts, int index) { - // NOTE: may return null - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return atts->mtl.resolves[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_mtl_attachments_ds_image(const _sg_attachments_t* atts) { - // NOTE: may return null - SOKOL_ASSERT(atts); - return atts->mtl.depth_stencil.image; -} - -_SOKOL_PRIVATE void _sg_mtl_begin_pass(const sg_pass* pass) { - SOKOL_ASSERT(pass); - SOKOL_ASSERT(_sg.mtl.cmd_queue); - SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); - SOKOL_ASSERT(nil == _sg.mtl.cur_drawable); - _sg_mtl_clear_state_cache(); - - const _sg_attachments_t* atts = _sg.cur_pass.atts; - const sg_swapchain* swapchain = &pass->swapchain; - const sg_pass_action* action = &pass->action; - - /* - if this is the first pass in the frame, create command buffers - - NOTE: we're creating two command buffers here, one with unretained references - for storing the regular commands, and one with retained references for - storing the presentDrawable call (this needs to hold on the drawable until - presentation has happened - and the easiest way to do this is to let the - command buffer manage the lifetime of the drawable). - - Also see: https://github.com/floooh/sokol/issues/762 - */ - if (nil == _sg.mtl.cmd_buffer) { - // block until the oldest frame in flight has finished - dispatch_semaphore_wait(_sg.mtl.sem, DISPATCH_TIME_FOREVER); - if (_sg.desc.mtl_use_command_buffer_with_retained_references) { - _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBuffer]; - } else { - _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBufferWithUnretainedReferences]; - } - [_sg.mtl.cmd_buffer enqueue]; - [_sg.mtl.cmd_buffer addCompletedHandler:^(id cmd_buf) { - // NOTE: this code is called on a different thread! - _SOKOL_UNUSED(cmd_buf); - dispatch_semaphore_signal(_sg.mtl.sem); - }]; - } - - // if this is first pass in frame, get uniform buffer base pointer - if (0 == _sg.mtl.cur_ub_base_ptr) { - _sg.mtl.cur_ub_base_ptr = (uint8_t*)[_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] contents]; - } - - MTLRenderPassDescriptor* pass_desc = [MTLRenderPassDescriptor renderPassDescriptor]; - SOKOL_ASSERT(pass_desc); - if (atts) { - // setup pass descriptor for offscreen rendering - SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_VALID); - for (NSUInteger i = 0; i < (NSUInteger)atts->cmn.num_colors; i++) { - const _sg_attachment_common_t* cmn_color_att = &atts->cmn.colors[i]; - const _sg_mtl_attachment_t* mtl_color_att = &atts->mtl.colors[i]; - const _sg_image_t* color_att_img = mtl_color_att->image; - const _sg_attachment_common_t* cmn_resolve_att = &atts->cmn.resolves[i]; - const _sg_mtl_attachment_t* mtl_resolve_att = &atts->mtl.resolves[i]; - const _sg_image_t* resolve_att_img = mtl_resolve_att->image; - SOKOL_ASSERT(color_att_img->slot.state == SG_RESOURCESTATE_VALID); - SOKOL_ASSERT(color_att_img->slot.id == cmn_color_att->image_id.id); - SOKOL_ASSERT(color_att_img->mtl.tex[color_att_img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - pass_desc.colorAttachments[i].loadAction = _sg_mtl_load_action(action->colors[i].load_action); - pass_desc.colorAttachments[i].storeAction = _sg_mtl_store_action(action->colors[i].store_action, resolve_att_img != 0); - sg_color c = action->colors[i].clear_value; - pass_desc.colorAttachments[i].clearColor = MTLClearColorMake(c.r, c.g, c.b, c.a); - pass_desc.colorAttachments[i].texture = _sg_mtl_id(color_att_img->mtl.tex[color_att_img->cmn.active_slot]); - pass_desc.colorAttachments[i].level = (NSUInteger)cmn_color_att->mip_level; - switch (color_att_img->cmn.type) { - case SG_IMAGETYPE_CUBE: - case SG_IMAGETYPE_ARRAY: - pass_desc.colorAttachments[i].slice = (NSUInteger)cmn_color_att->slice; - break; - case SG_IMAGETYPE_3D: - pass_desc.colorAttachments[i].depthPlane = (NSUInteger)cmn_color_att->slice; - break; - default: break; - } - if (resolve_att_img) { - SOKOL_ASSERT(resolve_att_img->slot.state == SG_RESOURCESTATE_VALID); - SOKOL_ASSERT(resolve_att_img->slot.id == cmn_resolve_att->image_id.id); - SOKOL_ASSERT(resolve_att_img->mtl.tex[resolve_att_img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - pass_desc.colorAttachments[i].resolveTexture = _sg_mtl_id(resolve_att_img->mtl.tex[resolve_att_img->cmn.active_slot]); - pass_desc.colorAttachments[i].resolveLevel = (NSUInteger)cmn_resolve_att->mip_level; - switch (resolve_att_img->cmn.type) { - case SG_IMAGETYPE_CUBE: - case SG_IMAGETYPE_ARRAY: - pass_desc.colorAttachments[i].resolveSlice = (NSUInteger)cmn_resolve_att->slice; - break; - case SG_IMAGETYPE_3D: - pass_desc.colorAttachments[i].resolveDepthPlane = (NSUInteger)cmn_resolve_att->slice; - break; - default: break; - } - } - } - const _sg_image_t* ds_att_img = atts->mtl.depth_stencil.image; - if (0 != ds_att_img) { - SOKOL_ASSERT(ds_att_img->slot.state == SG_RESOURCESTATE_VALID); - SOKOL_ASSERT(ds_att_img->slot.id == atts->cmn.depth_stencil.image_id.id); - SOKOL_ASSERT(ds_att_img->mtl.tex[ds_att_img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - pass_desc.depthAttachment.texture = _sg_mtl_id(ds_att_img->mtl.tex[ds_att_img->cmn.active_slot]); - pass_desc.depthAttachment.loadAction = _sg_mtl_load_action(action->depth.load_action); - pass_desc.depthAttachment.storeAction = _sg_mtl_store_action(action->depth.store_action, false); - pass_desc.depthAttachment.clearDepth = action->depth.clear_value; - const _sg_attachment_common_t* cmn_ds_att = &atts->cmn.depth_stencil; - switch (ds_att_img->cmn.type) { - case SG_IMAGETYPE_CUBE: - case SG_IMAGETYPE_ARRAY: - pass_desc.depthAttachment.slice = (NSUInteger)cmn_ds_att->slice; - break; - case SG_IMAGETYPE_3D: - pass_desc.depthAttachment.resolveDepthPlane = (NSUInteger)cmn_ds_att->slice; - break; - default: break; - } - if (_sg_is_depth_stencil_format(ds_att_img->cmn.pixel_format)) { - pass_desc.stencilAttachment.texture = _sg_mtl_id(ds_att_img->mtl.tex[ds_att_img->cmn.active_slot]); - pass_desc.stencilAttachment.loadAction = _sg_mtl_load_action(action->stencil.load_action); - pass_desc.stencilAttachment.storeAction = _sg_mtl_store_action(action->depth.store_action, false); - pass_desc.stencilAttachment.clearStencil = action->stencil.clear_value; - switch (ds_att_img->cmn.type) { - case SG_IMAGETYPE_CUBE: - case SG_IMAGETYPE_ARRAY: - pass_desc.stencilAttachment.slice = (NSUInteger)cmn_ds_att->slice; - break; - case SG_IMAGETYPE_3D: - pass_desc.stencilAttachment.resolveDepthPlane = (NSUInteger)cmn_ds_att->slice; - break; - default: break; - } - } - } - } else { - // setup pass descriptor for swapchain rendering - // - // NOTE: at least in macOS Sonoma this no longer seems to be the case, the - // current drawable is also valid in a minimized window - // === - // an MTKView current_drawable will not be valid if window is minimized, don't do any rendering in this case - if (0 == swapchain->metal.current_drawable) { - _sg.cur_pass.valid = false; - return; - } - // pin the swapchain resources into memory so that they outlive their command buffer - // (this is necessary because the command buffer doesn't retain references) - int pass_desc_ref = _sg_mtl_add_resource(pass_desc); - _sg_mtl_release_resource(_sg.frame_index, pass_desc_ref); - - _sg.mtl.cur_drawable = (__bridge id) swapchain->metal.current_drawable; - if (swapchain->sample_count > 1) { - // multi-sampling: render into msaa texture, resolve into drawable texture - id msaa_tex = (__bridge id) swapchain->metal.msaa_color_texture; - SOKOL_ASSERT(msaa_tex != nil); - pass_desc.colorAttachments[0].texture = msaa_tex; - pass_desc.colorAttachments[0].resolveTexture = _sg.mtl.cur_drawable.texture; - pass_desc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve; - } else { - // non-msaa: render into current_drawable - pass_desc.colorAttachments[0].texture = _sg.mtl.cur_drawable.texture; - pass_desc.colorAttachments[0].storeAction = MTLStoreActionStore; - } - pass_desc.colorAttachments[0].loadAction = _sg_mtl_load_action(action->colors[0].load_action); - const sg_color c = action->colors[0].clear_value; - pass_desc.colorAttachments[0].clearColor = MTLClearColorMake(c.r, c.g, c.b, c.a); - - // optional depth-stencil texture - if (swapchain->metal.depth_stencil_texture) { - id ds_tex = (__bridge id) swapchain->metal.depth_stencil_texture; - SOKOL_ASSERT(ds_tex != nil); - pass_desc.depthAttachment.texture = ds_tex; - pass_desc.depthAttachment.storeAction = MTLStoreActionDontCare; - pass_desc.depthAttachment.loadAction = _sg_mtl_load_action(action->depth.load_action); - pass_desc.depthAttachment.clearDepth = action->depth.clear_value; - if (_sg_is_depth_stencil_format(swapchain->depth_format)) { - pass_desc.stencilAttachment.texture = ds_tex; - pass_desc.stencilAttachment.storeAction = MTLStoreActionDontCare; - pass_desc.stencilAttachment.loadAction = _sg_mtl_load_action(action->stencil.load_action); - pass_desc.stencilAttachment.clearStencil = action->stencil.clear_value; - } - } - } - - // NOTE: at least in macOS Sonoma, the following is no longer the case, a valid - // render command encoder is also returned in a minimized window - // === - // create a render command encoder, this might return nil if window is minimized - _sg.mtl.cmd_encoder = [_sg.mtl.cmd_buffer renderCommandEncoderWithDescriptor:pass_desc]; - if (nil == _sg.mtl.cmd_encoder) { - _sg.cur_pass.valid = false; - return; - } - - #if defined(SOKOL_DEBUG) - if (pass->label) { - _sg.mtl.cmd_encoder.label = [NSString stringWithUTF8String:pass->label]; - } - #endif - - // bind the global uniform buffer, this only happens once per pass - _sg_mtl_bind_uniform_buffers(); -} - -_SOKOL_PRIVATE void _sg_mtl_end_pass(void) { - if (nil != _sg.mtl.cmd_encoder) { - [_sg.mtl.cmd_encoder endEncoding]; - // NOTE: MTLRenderCommandEncoder is autoreleased - _sg.mtl.cmd_encoder = nil; - } - // if this is a swapchain pass, present the drawable - if (nil != _sg.mtl.cur_drawable) { - [_sg.mtl.cmd_buffer presentDrawable:_sg.mtl.cur_drawable]; - _sg.mtl.cur_drawable = nil; - } -} - -_SOKOL_PRIVATE void _sg_mtl_commit(void) { - SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); - SOKOL_ASSERT(nil != _sg.mtl.cmd_buffer); - - // commit the frame's command buffer - [_sg.mtl.cmd_buffer commit]; - - // garbage-collect resources pending for release - _sg_mtl_garbage_collect(_sg.frame_index); - - // rotate uniform buffer slot - if (++_sg.mtl.cur_frame_rotate_index >= SG_NUM_INFLIGHT_FRAMES) { - _sg.mtl.cur_frame_rotate_index = 0; - } - _sg.mtl.cur_ub_offset = 0; - _sg.mtl.cur_ub_base_ptr = 0; - // NOTE: MTLCommandBuffer is autoreleased - _sg.mtl.cmd_buffer = nil; -} - -_SOKOL_PRIVATE void _sg_mtl_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); - SOKOL_ASSERT(_sg.cur_pass.height > 0); - MTLViewport vp; - vp.originX = (double) x; - vp.originY = (double) (origin_top_left ? y : (_sg.cur_pass.height - (y + h))); - vp.width = (double) w; - vp.height = (double) h; - vp.znear = 0.0; - vp.zfar = 1.0; - [_sg.mtl.cmd_encoder setViewport:vp]; -} - -_SOKOL_PRIVATE void _sg_mtl_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); - SOKOL_ASSERT(_sg.cur_pass.width > 0); - SOKOL_ASSERT(_sg.cur_pass.height > 0); - // clip against framebuffer rect - const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.width, _sg.cur_pass.height); - MTLScissorRect r; - r.x = (NSUInteger)clip.x; - r.y = (NSUInteger) (origin_top_left ? clip.y : (_sg.cur_pass.height - (clip.y + clip.h))); - r.width = (NSUInteger)clip.w; - r.height = (NSUInteger)clip.h; - [_sg.mtl.cmd_encoder setScissorRect:r]; -} - -_SOKOL_PRIVATE void _sg_mtl_apply_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); - SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); - - if (_sg.mtl.state_cache.cur_pipeline_id.id != pip->slot.id) { - _sg.mtl.state_cache.cur_pipeline = pip; - _sg.mtl.state_cache.cur_pipeline_id.id = pip->slot.id; - sg_color c = pip->cmn.blend_color; - [_sg.mtl.cmd_encoder setBlendColorRed:c.r green:c.g blue:c.b alpha:c.a]; - _sg_stats_add(metal.pipeline.num_set_blend_color, 1); - [_sg.mtl.cmd_encoder setCullMode:pip->mtl.cull_mode]; - _sg_stats_add(metal.pipeline.num_set_cull_mode, 1); - [_sg.mtl.cmd_encoder setFrontFacingWinding:pip->mtl.winding]; - _sg_stats_add(metal.pipeline.num_set_front_facing_winding, 1); - [_sg.mtl.cmd_encoder setStencilReferenceValue:pip->mtl.stencil_ref]; - _sg_stats_add(metal.pipeline.num_set_stencil_reference_value, 1); - [_sg.mtl.cmd_encoder setDepthBias:pip->cmn.depth.bias slopeScale:pip->cmn.depth.bias_slope_scale clamp:pip->cmn.depth.bias_clamp]; - _sg_stats_add(metal.pipeline.num_set_depth_bias, 1); - SOKOL_ASSERT(pip->mtl.rps != _SG_MTL_INVALID_SLOT_INDEX); - [_sg.mtl.cmd_encoder setRenderPipelineState:_sg_mtl_id(pip->mtl.rps)]; - _sg_stats_add(metal.pipeline.num_set_render_pipeline_state, 1); - SOKOL_ASSERT(pip->mtl.dss != _SG_MTL_INVALID_SLOT_INDEX); - [_sg.mtl.cmd_encoder setDepthStencilState:_sg_mtl_id(pip->mtl.dss)]; - _sg_stats_add(metal.pipeline.num_set_depth_stencil_state, 1); - } -} - -_SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) { - SOKOL_ASSERT(bnd); - SOKOL_ASSERT(bnd->pip); - SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); - - // store index buffer binding, this will be needed later in sg_draw() - _sg.mtl.state_cache.cur_indexbuffer = bnd->ib; - _sg.mtl.state_cache.cur_indexbuffer_offset = bnd->ib_offset; - if (bnd->ib) { - SOKOL_ASSERT(bnd->pip->cmn.index_type != SG_INDEXTYPE_NONE); - _sg.mtl.state_cache.cur_indexbuffer_id.id = bnd->ib->slot.id; - } else { - SOKOL_ASSERT(bnd->pip->cmn.index_type == SG_INDEXTYPE_NONE); - _sg.mtl.state_cache.cur_indexbuffer_id.id = SG_INVALID_ID; - } - - // apply vertex buffers - for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_vbs; slot++) { - const _sg_buffer_t* vb = bnd->vbs[slot]; - const int vb_offset = bnd->vb_offsets[slot]; - if ((_sg.mtl.state_cache.cur_vertexbuffer_ids[slot].id != vb->slot.id) || - (_sg.mtl.state_cache.cur_vertexbuffer_offsets[slot] != vb_offset)) - { - _sg.mtl.state_cache.cur_vertexbuffer_offsets[slot] = vb_offset; - const NSUInteger mtl_slot = SG_MAX_SHADERSTAGE_UBS + slot; - if (_sg.mtl.state_cache.cur_vertexbuffer_ids[slot].id != vb->slot.id) { - _sg.mtl.state_cache.cur_vertexbuffer_ids[slot].id = vb->slot.id; - SOKOL_ASSERT(vb->mtl.buf[vb->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - [_sg.mtl.cmd_encoder setVertexBuffer:_sg_mtl_id(vb->mtl.buf[vb->cmn.active_slot]) - offset:(NSUInteger)vb_offset - atIndex:mtl_slot]; - } else { - [_sg.mtl.cmd_encoder setVertexBufferOffset:(NSUInteger)vb_offset atIndex:mtl_slot]; - } - _sg_stats_add(metal.bindings.num_set_vertex_buffer, 1); - } - } - - // apply vertex stage images - for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_vs_imgs; slot++) { - const _sg_image_t* img = bnd->vs_imgs[slot]; - if (_sg.mtl.state_cache.cur_vs_image_ids[slot].id != img->slot.id) { - _sg.mtl.state_cache.cur_vs_image_ids[slot].id = img->slot.id; - SOKOL_ASSERT(img->mtl.tex[img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - [_sg.mtl.cmd_encoder setVertexTexture:_sg_mtl_id(img->mtl.tex[img->cmn.active_slot]) atIndex:slot]; - _sg_stats_add(metal.bindings.num_set_vertex_texture, 1); - } - } - - // apply vertex stage samplers - for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_vs_smps; slot++) { - const _sg_sampler_t* smp = bnd->vs_smps[slot]; - if (_sg.mtl.state_cache.cur_vs_sampler_ids[slot].id != smp->slot.id) { - _sg.mtl.state_cache.cur_vs_sampler_ids[slot].id = smp->slot.id; - SOKOL_ASSERT(smp->mtl.sampler_state != _SG_MTL_INVALID_SLOT_INDEX); - [_sg.mtl.cmd_encoder setVertexSamplerState:_sg_mtl_id(smp->mtl.sampler_state) atIndex:slot]; - _sg_stats_add(metal.bindings.num_set_vertex_sampler_state, 1); - } - } - - // apply vertex stage storage buffers - for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_vs_sbufs; slot++) { - const _sg_buffer_t* sbuf = bnd->vs_sbufs[slot]; - if (_sg.mtl.state_cache.cur_vs_storagebuffer_ids[slot].id != sbuf->slot.id) { - _sg.mtl.state_cache.cur_vs_storagebuffer_ids[slot].id = sbuf->slot.id; - SOKOL_ASSERT(sbuf->mtl.buf[sbuf->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - const NSUInteger mtl_slot = SG_MAX_SHADERSTAGE_UBS + SG_MAX_VERTEX_BUFFERS + slot; - [_sg.mtl.cmd_encoder setVertexBuffer:_sg_mtl_id(sbuf->mtl.buf[sbuf->cmn.active_slot]) offset:0 atIndex:mtl_slot]; - _sg_stats_add(metal.bindings.num_set_vertex_buffer, 1); - } - } - - // apply fragment stage images - for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_fs_imgs; slot++) { - const _sg_image_t* img = bnd->fs_imgs[slot]; - if (_sg.mtl.state_cache.cur_fs_image_ids[slot].id != img->slot.id) { - _sg.mtl.state_cache.cur_fs_image_ids[slot].id = img->slot.id; - SOKOL_ASSERT(img->mtl.tex[img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - [_sg.mtl.cmd_encoder setFragmentTexture:_sg_mtl_id(img->mtl.tex[img->cmn.active_slot]) atIndex:slot]; - _sg_stats_add(metal.bindings.num_set_fragment_texture, 1); - } - } - - // apply fragment stage samplers - for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_fs_smps; slot++) { - const _sg_sampler_t* smp = bnd->fs_smps[slot]; - if (_sg.mtl.state_cache.cur_fs_sampler_ids[slot].id != smp->slot.id) { - _sg.mtl.state_cache.cur_fs_sampler_ids[slot].id = smp->slot.id; - SOKOL_ASSERT(smp->mtl.sampler_state != _SG_MTL_INVALID_SLOT_INDEX); - [_sg.mtl.cmd_encoder setFragmentSamplerState:_sg_mtl_id(smp->mtl.sampler_state) atIndex:slot]; - _sg_stats_add(metal.bindings.num_set_fragment_sampler_state, 1); - } - } - - // apply fragment stage storage buffers - for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_fs_sbufs; slot++) { - const _sg_buffer_t* sbuf = bnd->fs_sbufs[slot]; - if (_sg.mtl.state_cache.cur_fs_storagebuffer_ids[slot].id != sbuf->slot.id) { - _sg.mtl.state_cache.cur_fs_storagebuffer_ids[slot].id = sbuf->slot.id; - SOKOL_ASSERT(sbuf->mtl.buf[sbuf->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - const NSUInteger mtl_slot = SG_MAX_SHADERSTAGE_UBS + slot; - [_sg.mtl.cmd_encoder setFragmentBuffer:_sg_mtl_id(sbuf->mtl.buf[sbuf->cmn.active_slot]) offset:0 atIndex:mtl_slot]; - _sg_stats_add(metal.bindings.num_set_fragment_buffer, 1); - } - } - - return true; -} - -_SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { - SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); - SOKOL_ASSERT(((size_t)_sg.mtl.cur_ub_offset + data->size) <= (size_t)_sg.mtl.ub_size); - SOKOL_ASSERT((_sg.mtl.cur_ub_offset & (_SG_MTL_UB_ALIGN-1)) == 0); - SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline && _sg.mtl.state_cache.cur_pipeline->shader); - SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline->slot.id == _sg.mtl.state_cache.cur_pipeline_id.id); - SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline->shader->slot.id == _sg.mtl.state_cache.cur_pipeline->cmn.shader_id.id); - SOKOL_ASSERT(ub_index < _sg.mtl.state_cache.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); - SOKOL_ASSERT(data->size == _sg.mtl.state_cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); - - // copy to global uniform buffer, record offset into cmd encoder, and advance offset - uint8_t* dst = &_sg.mtl.cur_ub_base_ptr[_sg.mtl.cur_ub_offset]; - memcpy(dst, data->ptr, data->size); - if (stage_index == SG_SHADERSTAGE_VS) { - [_sg.mtl.cmd_encoder setVertexBufferOffset:(NSUInteger)_sg.mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; - _sg_stats_add(metal.uniforms.num_set_vertex_buffer_offset, 1); - } else { - [_sg.mtl.cmd_encoder setFragmentBufferOffset:(NSUInteger)_sg.mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; - _sg_stats_add(metal.uniforms.num_set_fragment_buffer_offset, 1); - } - _sg.mtl.cur_ub_offset = _sg_roundup(_sg.mtl.cur_ub_offset + (int)data->size, _SG_MTL_UB_ALIGN); -} - -_SOKOL_PRIVATE void _sg_mtl_draw(int base_element, int num_elements, int num_instances) { - SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); - SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline && (_sg.mtl.state_cache.cur_pipeline->slot.id == _sg.mtl.state_cache.cur_pipeline_id.id)); - if (SG_INDEXTYPE_NONE != _sg.mtl.state_cache.cur_pipeline->cmn.index_type) { - // indexed rendering - SOKOL_ASSERT(_sg.mtl.state_cache.cur_indexbuffer && (_sg.mtl.state_cache.cur_indexbuffer->slot.id == _sg.mtl.state_cache.cur_indexbuffer_id.id)); - const _sg_buffer_t* ib = _sg.mtl.state_cache.cur_indexbuffer; - SOKOL_ASSERT(ib->mtl.buf[ib->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - const NSUInteger index_buffer_offset = (NSUInteger) (_sg.mtl.state_cache.cur_indexbuffer_offset + base_element * _sg.mtl.state_cache.cur_pipeline->mtl.index_size); - [_sg.mtl.cmd_encoder drawIndexedPrimitives:_sg.mtl.state_cache.cur_pipeline->mtl.prim_type - indexCount:(NSUInteger)num_elements - indexType:_sg.mtl.state_cache.cur_pipeline->mtl.index_type - indexBuffer:_sg_mtl_id(ib->mtl.buf[ib->cmn.active_slot]) - indexBufferOffset:index_buffer_offset - instanceCount:(NSUInteger)num_instances]; - } else { - // non-indexed rendering - [_sg.mtl.cmd_encoder drawPrimitives:_sg.mtl.state_cache.cur_pipeline->mtl.prim_type - vertexStart:(NSUInteger)base_element - vertexCount:(NSUInteger)num_elements - instanceCount:(NSUInteger)num_instances]; - } -} - -_SOKOL_PRIVATE void _sg_mtl_update_buffer(_sg_buffer_t* buf, const sg_range* data) { - SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); - if (++buf->cmn.active_slot >= buf->cmn.num_slots) { - buf->cmn.active_slot = 0; - } - __unsafe_unretained id mtl_buf = _sg_mtl_id(buf->mtl.buf[buf->cmn.active_slot]); - void* dst_ptr = [mtl_buf contents]; - memcpy(dst_ptr, data->ptr, data->size); - #if defined(_SG_TARGET_MACOS) - if (_sg_mtl_resource_options_storage_mode_managed_or_shared() == MTLResourceStorageModeManaged) { - [mtl_buf didModifyRange:NSMakeRange(0, data->size)]; - } - #endif -} - -_SOKOL_PRIVATE void _sg_mtl_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { - SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); - if (new_frame) { - if (++buf->cmn.active_slot >= buf->cmn.num_slots) { - buf->cmn.active_slot = 0; - } - } - __unsafe_unretained id mtl_buf = _sg_mtl_id(buf->mtl.buf[buf->cmn.active_slot]); - uint8_t* dst_ptr = (uint8_t*) [mtl_buf contents]; - dst_ptr += buf->cmn.append_pos; - memcpy(dst_ptr, data->ptr, data->size); - #if defined(_SG_TARGET_MACOS) - if (_sg_mtl_resource_options_storage_mode_managed_or_shared() == MTLResourceStorageModeManaged) { - [mtl_buf didModifyRange:NSMakeRange((NSUInteger)buf->cmn.append_pos, (NSUInteger)data->size)]; - } - #endif -} - -_SOKOL_PRIVATE void _sg_mtl_update_image(_sg_image_t* img, const sg_image_data* data) { - SOKOL_ASSERT(img && data); - if (++img->cmn.active_slot >= img->cmn.num_slots) { - img->cmn.active_slot = 0; - } - __unsafe_unretained id mtl_tex = _sg_mtl_id(img->mtl.tex[img->cmn.active_slot]); - _sg_mtl_copy_image_data(img, mtl_tex, data); -} - -_SOKOL_PRIVATE void _sg_mtl_push_debug_group(const char* name) { - SOKOL_ASSERT(name); - if (_sg.mtl.cmd_encoder) { - [_sg.mtl.cmd_encoder pushDebugGroup:[NSString stringWithUTF8String:name]]; - } -} - -_SOKOL_PRIVATE void _sg_mtl_pop_debug_group(void) { - if (_sg.mtl.cmd_encoder) { - [_sg.mtl.cmd_encoder popDebugGroup]; - } -} - -// ██ ██ ███████ ██████ ██████ ██████ ██ ██ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██ █ ██ █████ ██████ ██ ███ ██████ ██ ██ ██████ ███████ ██ █████ █████ ██ ██ ██ ██ ██ -// ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███ ███ ███████ ██████ ██████ ██ ██████ ██████ ██ ██ ██████ ██ ██ ███████ ██ ████ ██████ -// -// >>webgpu -// >>wgpu -#elif defined(SOKOL_WGPU) - -_SOKOL_PRIVATE WGPUBufferUsageFlags _sg_wgpu_buffer_usage(sg_buffer_type t, sg_usage u) { - WGPUBufferUsageFlags res = 0; - if (SG_BUFFERTYPE_VERTEXBUFFER == t) { - res = WGPUBufferUsage_Vertex; - } else if (SG_BUFFERTYPE_STORAGEBUFFER == t) { - res = WGPUBufferUsage_Storage; - } else { - res = WGPUBufferUsage_Index; - } - if (SG_USAGE_IMMUTABLE != u) { - res |= WGPUBufferUsage_CopyDst; - } - return res; -} - -_SOKOL_PRIVATE WGPULoadOp _sg_wgpu_load_op(WGPUTextureView view, sg_load_action a) { - if (0 == view) { - return WGPULoadOp_Undefined; - } else switch (a) { - case SG_LOADACTION_CLEAR: - case SG_LOADACTION_DONTCARE: - return WGPULoadOp_Clear; - case SG_LOADACTION_LOAD: - return WGPULoadOp_Load; - default: - SOKOL_UNREACHABLE; - return WGPULoadOp_Force32; - } -} - -_SOKOL_PRIVATE WGPUStoreOp _sg_wgpu_store_op(WGPUTextureView view, sg_store_action a) { - if (0 == view) { - return WGPUStoreOp_Undefined; - } else switch (a) { - case SG_STOREACTION_STORE: - return WGPUStoreOp_Store; - case SG_STOREACTION_DONTCARE: - return WGPUStoreOp_Discard; - default: - SOKOL_UNREACHABLE; - return WGPUStoreOp_Force32; - } -} - -_SOKOL_PRIVATE WGPUTextureViewDimension _sg_wgpu_texture_view_dimension(sg_image_type t) { - switch (t) { - case SG_IMAGETYPE_2D: return WGPUTextureViewDimension_2D; - case SG_IMAGETYPE_CUBE: return WGPUTextureViewDimension_Cube; - case SG_IMAGETYPE_3D: return WGPUTextureViewDimension_3D; - case SG_IMAGETYPE_ARRAY: return WGPUTextureViewDimension_2DArray; - default: SOKOL_UNREACHABLE; return WGPUTextureViewDimension_Force32; - } -} - -_SOKOL_PRIVATE WGPUTextureDimension _sg_wgpu_texture_dimension(sg_image_type t) { - if (SG_IMAGETYPE_3D == t) { - return WGPUTextureDimension_3D; - } else { - return WGPUTextureDimension_2D; - } -} - -_SOKOL_PRIVATE WGPUTextureSampleType _sg_wgpu_texture_sample_type(sg_image_sample_type t) { - switch (t) { - case SG_IMAGESAMPLETYPE_FLOAT: return WGPUTextureSampleType_Float; - case SG_IMAGESAMPLETYPE_DEPTH: return WGPUTextureSampleType_Depth; - case SG_IMAGESAMPLETYPE_SINT: return WGPUTextureSampleType_Sint; - case SG_IMAGESAMPLETYPE_UINT: return WGPUTextureSampleType_Uint; - case SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT: return WGPUTextureSampleType_UnfilterableFloat; - default: SOKOL_UNREACHABLE; return WGPUTextureSampleType_Force32; - } -} - -_SOKOL_PRIVATE WGPUSamplerBindingType _sg_wgpu_sampler_binding_type(sg_sampler_type t) { - switch (t) { - case SG_SAMPLERTYPE_FILTERING: return WGPUSamplerBindingType_Filtering; - case SG_SAMPLERTYPE_COMPARISON: return WGPUSamplerBindingType_Comparison; - case SG_SAMPLERTYPE_NONFILTERING: return WGPUSamplerBindingType_NonFiltering; - default: SOKOL_UNREACHABLE; return WGPUSamplerBindingType_Force32; - } -} - -_SOKOL_PRIVATE WGPUAddressMode _sg_wgpu_sampler_address_mode(sg_wrap m) { - switch (m) { - case SG_WRAP_REPEAT: - return WGPUAddressMode_Repeat; - case SG_WRAP_CLAMP_TO_EDGE: - case SG_WRAP_CLAMP_TO_BORDER: - return WGPUAddressMode_ClampToEdge; - case SG_WRAP_MIRRORED_REPEAT: - return WGPUAddressMode_MirrorRepeat; - default: - SOKOL_UNREACHABLE; - return WGPUAddressMode_Force32; - } -} - -_SOKOL_PRIVATE WGPUFilterMode _sg_wgpu_sampler_minmag_filter(sg_filter f) { - switch (f) { - case SG_FILTER_NEAREST: - return WGPUFilterMode_Nearest; - case SG_FILTER_LINEAR: - return WGPUFilterMode_Linear; - default: - SOKOL_UNREACHABLE; - return WGPUFilterMode_Force32; - } -} - -_SOKOL_PRIVATE WGPUMipmapFilterMode _sg_wgpu_sampler_mipmap_filter(sg_filter f) { - switch (f) { - case SG_FILTER_NEAREST: - return WGPUMipmapFilterMode_Nearest; - case SG_FILTER_LINEAR: - return WGPUMipmapFilterMode_Linear; - default: - SOKOL_UNREACHABLE; - return WGPUMipmapFilterMode_Force32; - } -} - -_SOKOL_PRIVATE WGPUIndexFormat _sg_wgpu_indexformat(sg_index_type t) { - // NOTE: there's no WGPUIndexFormat_None - return (t == SG_INDEXTYPE_UINT16) ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32; -} - -_SOKOL_PRIVATE WGPUIndexFormat _sg_wgpu_stripindexformat(sg_primitive_type prim_type, sg_index_type idx_type) { - if (idx_type == SG_INDEXTYPE_NONE) { - return WGPUIndexFormat_Undefined; - } else if ((prim_type == SG_PRIMITIVETYPE_LINE_STRIP) || (prim_type == SG_PRIMITIVETYPE_TRIANGLE_STRIP)) { - return _sg_wgpu_indexformat(idx_type); - } else { - return WGPUIndexFormat_Undefined; - } -} - -_SOKOL_PRIVATE WGPUVertexStepMode _sg_wgpu_stepmode(sg_vertex_step s) { - return (s == SG_VERTEXSTEP_PER_VERTEX) ? WGPUVertexStepMode_Vertex : WGPUVertexStepMode_Instance; -} - -_SOKOL_PRIVATE WGPUVertexFormat _sg_wgpu_vertexformat(sg_vertex_format f) { - switch (f) { - case SG_VERTEXFORMAT_FLOAT: return WGPUVertexFormat_Float32; - case SG_VERTEXFORMAT_FLOAT2: return WGPUVertexFormat_Float32x2; - case SG_VERTEXFORMAT_FLOAT3: return WGPUVertexFormat_Float32x3; - case SG_VERTEXFORMAT_FLOAT4: return WGPUVertexFormat_Float32x4; - case SG_VERTEXFORMAT_BYTE4: return WGPUVertexFormat_Sint8x4; - case SG_VERTEXFORMAT_BYTE4N: return WGPUVertexFormat_Snorm8x4; - case SG_VERTEXFORMAT_UBYTE4: return WGPUVertexFormat_Uint8x4; - case SG_VERTEXFORMAT_UBYTE4N: return WGPUVertexFormat_Unorm8x4; - case SG_VERTEXFORMAT_SHORT2: return WGPUVertexFormat_Sint16x2; - case SG_VERTEXFORMAT_SHORT2N: return WGPUVertexFormat_Snorm16x2; - case SG_VERTEXFORMAT_USHORT2N: return WGPUVertexFormat_Unorm16x2; - case SG_VERTEXFORMAT_SHORT4: return WGPUVertexFormat_Sint16x4; - case SG_VERTEXFORMAT_SHORT4N: return WGPUVertexFormat_Snorm16x4; - case SG_VERTEXFORMAT_USHORT4N: return WGPUVertexFormat_Unorm16x4; - case SG_VERTEXFORMAT_HALF2: return WGPUVertexFormat_Float16x2; - case SG_VERTEXFORMAT_HALF4: return WGPUVertexFormat_Float16x4; - // FIXME! UINT10_N2 (see https://github.com/gpuweb/gpuweb/issues/4275) - case SG_VERTEXFORMAT_UINT10_N2: return WGPUVertexFormat_Undefined; - default: - SOKOL_UNREACHABLE; - return WGPUVertexFormat_Force32; - } -} - -_SOKOL_PRIVATE WGPUPrimitiveTopology _sg_wgpu_topology(sg_primitive_type t) { - switch (t) { - case SG_PRIMITIVETYPE_POINTS: return WGPUPrimitiveTopology_PointList; - case SG_PRIMITIVETYPE_LINES: return WGPUPrimitiveTopology_LineList; - case SG_PRIMITIVETYPE_LINE_STRIP: return WGPUPrimitiveTopology_LineStrip; - case SG_PRIMITIVETYPE_TRIANGLES: return WGPUPrimitiveTopology_TriangleList; - case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return WGPUPrimitiveTopology_TriangleStrip; - default: - SOKOL_UNREACHABLE; - return WGPUPrimitiveTopology_Force32; - } -} - -_SOKOL_PRIVATE WGPUFrontFace _sg_wgpu_frontface(sg_face_winding fw) { - return (fw == SG_FACEWINDING_CCW) ? WGPUFrontFace_CCW : WGPUFrontFace_CW; -} - -_SOKOL_PRIVATE WGPUCullMode _sg_wgpu_cullmode(sg_cull_mode cm) { - switch (cm) { - case SG_CULLMODE_NONE: return WGPUCullMode_None; - case SG_CULLMODE_FRONT: return WGPUCullMode_Front; - case SG_CULLMODE_BACK: return WGPUCullMode_Back; - default: - SOKOL_UNREACHABLE; - return WGPUCullMode_Force32; - } -} - -_SOKOL_PRIVATE WGPUTextureFormat _sg_wgpu_textureformat(sg_pixel_format p) { - switch (p) { - case SG_PIXELFORMAT_NONE: return WGPUTextureFormat_Undefined; - case SG_PIXELFORMAT_R8: return WGPUTextureFormat_R8Unorm; - case SG_PIXELFORMAT_R8SN: return WGPUTextureFormat_R8Snorm; - case SG_PIXELFORMAT_R8UI: return WGPUTextureFormat_R8Uint; - case SG_PIXELFORMAT_R8SI: return WGPUTextureFormat_R8Sint; - case SG_PIXELFORMAT_R16UI: return WGPUTextureFormat_R16Uint; - case SG_PIXELFORMAT_R16SI: return WGPUTextureFormat_R16Sint; - case SG_PIXELFORMAT_R16F: return WGPUTextureFormat_R16Float; - case SG_PIXELFORMAT_RG8: return WGPUTextureFormat_RG8Unorm; - case SG_PIXELFORMAT_RG8SN: return WGPUTextureFormat_RG8Snorm; - case SG_PIXELFORMAT_RG8UI: return WGPUTextureFormat_RG8Uint; - case SG_PIXELFORMAT_RG8SI: return WGPUTextureFormat_RG8Sint; - case SG_PIXELFORMAT_R32UI: return WGPUTextureFormat_R32Uint; - case SG_PIXELFORMAT_R32SI: return WGPUTextureFormat_R32Sint; - case SG_PIXELFORMAT_R32F: return WGPUTextureFormat_R32Float; - case SG_PIXELFORMAT_RG16UI: return WGPUTextureFormat_RG16Uint; - case SG_PIXELFORMAT_RG16SI: return WGPUTextureFormat_RG16Sint; - case SG_PIXELFORMAT_RG16F: return WGPUTextureFormat_RG16Float; - case SG_PIXELFORMAT_RGBA8: return WGPUTextureFormat_RGBA8Unorm; - case SG_PIXELFORMAT_SRGB8A8: return WGPUTextureFormat_RGBA8UnormSrgb; - case SG_PIXELFORMAT_RGBA8SN: return WGPUTextureFormat_RGBA8Snorm; - case SG_PIXELFORMAT_RGBA8UI: return WGPUTextureFormat_RGBA8Uint; - case SG_PIXELFORMAT_RGBA8SI: return WGPUTextureFormat_RGBA8Sint; - case SG_PIXELFORMAT_BGRA8: return WGPUTextureFormat_BGRA8Unorm; - case SG_PIXELFORMAT_RGB10A2: return WGPUTextureFormat_RGB10A2Unorm; - case SG_PIXELFORMAT_RG11B10F: return WGPUTextureFormat_RG11B10Ufloat; - case SG_PIXELFORMAT_RG32UI: return WGPUTextureFormat_RG32Uint; - case SG_PIXELFORMAT_RG32SI: return WGPUTextureFormat_RG32Sint; - case SG_PIXELFORMAT_RG32F: return WGPUTextureFormat_RG32Float; - case SG_PIXELFORMAT_RGBA16UI: return WGPUTextureFormat_RGBA16Uint; - case SG_PIXELFORMAT_RGBA16SI: return WGPUTextureFormat_RGBA16Sint; - case SG_PIXELFORMAT_RGBA16F: return WGPUTextureFormat_RGBA16Float; - case SG_PIXELFORMAT_RGBA32UI: return WGPUTextureFormat_RGBA32Uint; - case SG_PIXELFORMAT_RGBA32SI: return WGPUTextureFormat_RGBA32Sint; - case SG_PIXELFORMAT_RGBA32F: return WGPUTextureFormat_RGBA32Float; - case SG_PIXELFORMAT_DEPTH: return WGPUTextureFormat_Depth32Float; - case SG_PIXELFORMAT_DEPTH_STENCIL: return WGPUTextureFormat_Depth32FloatStencil8; - case SG_PIXELFORMAT_BC1_RGBA: return WGPUTextureFormat_BC1RGBAUnorm; - case SG_PIXELFORMAT_BC2_RGBA: return WGPUTextureFormat_BC2RGBAUnorm; - case SG_PIXELFORMAT_BC3_RGBA: return WGPUTextureFormat_BC3RGBAUnorm; - case SG_PIXELFORMAT_BC3_SRGBA: return WGPUTextureFormat_BC3RGBAUnormSrgb; - case SG_PIXELFORMAT_BC4_R: return WGPUTextureFormat_BC4RUnorm; - case SG_PIXELFORMAT_BC4_RSN: return WGPUTextureFormat_BC4RSnorm; - case SG_PIXELFORMAT_BC5_RG: return WGPUTextureFormat_BC5RGUnorm; - case SG_PIXELFORMAT_BC5_RGSN: return WGPUTextureFormat_BC5RGSnorm; - case SG_PIXELFORMAT_BC6H_RGBF: return WGPUTextureFormat_BC6HRGBFloat; - case SG_PIXELFORMAT_BC6H_RGBUF: return WGPUTextureFormat_BC6HRGBUfloat; - case SG_PIXELFORMAT_BC7_RGBA: return WGPUTextureFormat_BC7RGBAUnorm; - case SG_PIXELFORMAT_BC7_SRGBA: return WGPUTextureFormat_BC7RGBAUnormSrgb; - case SG_PIXELFORMAT_ETC2_RGB8: return WGPUTextureFormat_ETC2RGB8Unorm; - case SG_PIXELFORMAT_ETC2_RGB8A1: return WGPUTextureFormat_ETC2RGB8A1Unorm; - case SG_PIXELFORMAT_ETC2_RGBA8: return WGPUTextureFormat_ETC2RGBA8Unorm; - case SG_PIXELFORMAT_ETC2_SRGB8: return WGPUTextureFormat_ETC2RGB8UnormSrgb; - case SG_PIXELFORMAT_ETC2_SRGB8A8: return WGPUTextureFormat_ETC2RGBA8UnormSrgb; - case SG_PIXELFORMAT_EAC_R11: return WGPUTextureFormat_EACR11Unorm; - case SG_PIXELFORMAT_EAC_R11SN: return WGPUTextureFormat_EACR11Snorm; - case SG_PIXELFORMAT_EAC_RG11: return WGPUTextureFormat_EACRG11Unorm; - case SG_PIXELFORMAT_EAC_RG11SN: return WGPUTextureFormat_EACRG11Snorm; - case SG_PIXELFORMAT_RGB9E5: return WGPUTextureFormat_RGB9E5Ufloat; - case SG_PIXELFORMAT_ASTC_4x4_RGBA: return WGPUTextureFormat_ASTC4x4Unorm; - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return WGPUTextureFormat_ASTC4x4UnormSrgb; - // NOT SUPPORTED - case SG_PIXELFORMAT_R16: - case SG_PIXELFORMAT_R16SN: - case SG_PIXELFORMAT_RG16: - case SG_PIXELFORMAT_RG16SN: - case SG_PIXELFORMAT_RGBA16: - case SG_PIXELFORMAT_RGBA16SN: - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: - return WGPUTextureFormat_Undefined; - - default: - SOKOL_UNREACHABLE; - return WGPUTextureFormat_Force32; - } -} - -_SOKOL_PRIVATE WGPUCompareFunction _sg_wgpu_comparefunc(sg_compare_func f) { - switch (f) { - case SG_COMPAREFUNC_NEVER: return WGPUCompareFunction_Never; - case SG_COMPAREFUNC_LESS: return WGPUCompareFunction_Less; - case SG_COMPAREFUNC_EQUAL: return WGPUCompareFunction_Equal; - case SG_COMPAREFUNC_LESS_EQUAL: return WGPUCompareFunction_LessEqual; - case SG_COMPAREFUNC_GREATER: return WGPUCompareFunction_Greater; - case SG_COMPAREFUNC_NOT_EQUAL: return WGPUCompareFunction_NotEqual; - case SG_COMPAREFUNC_GREATER_EQUAL: return WGPUCompareFunction_GreaterEqual; - case SG_COMPAREFUNC_ALWAYS: return WGPUCompareFunction_Always; - default: - SOKOL_UNREACHABLE; - return WGPUCompareFunction_Force32; - } -} - -_SOKOL_PRIVATE WGPUStencilOperation _sg_wgpu_stencilop(sg_stencil_op op) { - switch (op) { - case SG_STENCILOP_KEEP: return WGPUStencilOperation_Keep; - case SG_STENCILOP_ZERO: return WGPUStencilOperation_Zero; - case SG_STENCILOP_REPLACE: return WGPUStencilOperation_Replace; - case SG_STENCILOP_INCR_CLAMP: return WGPUStencilOperation_IncrementClamp; - case SG_STENCILOP_DECR_CLAMP: return WGPUStencilOperation_DecrementClamp; - case SG_STENCILOP_INVERT: return WGPUStencilOperation_Invert; - case SG_STENCILOP_INCR_WRAP: return WGPUStencilOperation_IncrementWrap; - case SG_STENCILOP_DECR_WRAP: return WGPUStencilOperation_DecrementWrap; - default: - SOKOL_UNREACHABLE; - return WGPUStencilOperation_Force32; - } -} - -_SOKOL_PRIVATE WGPUBlendOperation _sg_wgpu_blendop(sg_blend_op op) { - switch (op) { - case SG_BLENDOP_ADD: return WGPUBlendOperation_Add; - case SG_BLENDOP_SUBTRACT: return WGPUBlendOperation_Subtract; - case SG_BLENDOP_REVERSE_SUBTRACT: return WGPUBlendOperation_ReverseSubtract; - default: - SOKOL_UNREACHABLE; - return WGPUBlendOperation_Force32; - } -} - -_SOKOL_PRIVATE WGPUBlendFactor _sg_wgpu_blendfactor(sg_blend_factor f) { - switch (f) { - case SG_BLENDFACTOR_ZERO: return WGPUBlendFactor_Zero; - case SG_BLENDFACTOR_ONE: return WGPUBlendFactor_One; - case SG_BLENDFACTOR_SRC_COLOR: return WGPUBlendFactor_Src; - case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return WGPUBlendFactor_OneMinusSrc; - case SG_BLENDFACTOR_SRC_ALPHA: return WGPUBlendFactor_SrcAlpha; - case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return WGPUBlendFactor_OneMinusSrcAlpha; - case SG_BLENDFACTOR_DST_COLOR: return WGPUBlendFactor_Dst; - case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return WGPUBlendFactor_OneMinusDst; - case SG_BLENDFACTOR_DST_ALPHA: return WGPUBlendFactor_DstAlpha; - case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return WGPUBlendFactor_OneMinusDstAlpha; - case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return WGPUBlendFactor_SrcAlphaSaturated; - case SG_BLENDFACTOR_BLEND_COLOR: return WGPUBlendFactor_Constant; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return WGPUBlendFactor_OneMinusConstant; - // FIXME: separate blend alpha value not supported? - case SG_BLENDFACTOR_BLEND_ALPHA: return WGPUBlendFactor_Constant; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return WGPUBlendFactor_OneMinusConstant; - default: - SOKOL_UNREACHABLE; - return WGPUBlendFactor_Force32; - } -} - -_SOKOL_PRIVATE WGPUColorWriteMaskFlags _sg_wgpu_colorwritemask(uint8_t m) { - WGPUColorWriteMaskFlags res = 0; - if (0 != (m & SG_COLORMASK_R)) { - res |= WGPUColorWriteMask_Red; - } - if (0 != (m & SG_COLORMASK_G)) { - res |= WGPUColorWriteMask_Green; - } - if (0 != (m & SG_COLORMASK_B)) { - res |= WGPUColorWriteMask_Blue; - } - if (0 != (m & SG_COLORMASK_A)) { - res |= WGPUColorWriteMask_Alpha; - } - return res; -} - -// image/sampler binding on wgpu follows this convention: -// -// - all images and sampler are in @group(1) -// - vertex stage images start at @binding(0) -// - vertex stage samplers start at @binding(16) -// - vertex stage storage buffers start at @binding(32) -// - fragment stage images start at @binding(48) -// - fragment stage samplers start at @binding(64) -// - fragment stage storage buffers start at @binding(80) -// -_SOKOL_PRIVATE uint32_t _sg_wgpu_image_binding(sg_shader_stage stage, int img_slot) { - SOKOL_ASSERT((img_slot >= 0) && (img_slot < 16)); - if (SG_SHADERSTAGE_VS == stage) { - return 0 + (uint32_t)img_slot; - } else { - return 48 + (uint32_t)img_slot; - } -} - -_SOKOL_PRIVATE uint32_t _sg_wgpu_sampler_binding(sg_shader_stage stage, int smp_slot) { - SOKOL_ASSERT((smp_slot >= 0) && (smp_slot < 16)); - if (SG_SHADERSTAGE_VS == stage) { - return 16 + (uint32_t)smp_slot; - } else { - return 64 + (uint32_t)smp_slot; - } -} - -_SOKOL_PRIVATE uint32_t _sg_wgpu_storagebuffer_binding(sg_shader_stage stage, int sbuf_slot) { - SOKOL_ASSERT((sbuf_slot >= 0) && (sbuf_slot < 16)); - if (SG_SHADERSTAGE_VS == stage) { - return 32 + (uint32_t)sbuf_slot; - } else { - return 80 + (uint32_t)sbuf_slot; - } -} - -_SOKOL_PRIVATE WGPUShaderStage _sg_wgpu_shader_stage(sg_shader_stage stage) { - switch (stage) { - case SG_SHADERSTAGE_VS: return WGPUShaderStage_Vertex; - case SG_SHADERSTAGE_FS: return WGPUShaderStage_Fragment; - default: SOKOL_UNREACHABLE; return WGPUShaderStage_None; - } -} - -_SOKOL_PRIVATE void _sg_wgpu_init_caps(void) { - _sg.backend = SG_BACKEND_WGPU; - _sg.features.origin_top_left = true; - _sg.features.image_clamp_to_border = false; - _sg.features.mrt_independent_blend_state = true; - _sg.features.mrt_independent_write_mask = true; - _sg.features.storage_buffer = true; - - wgpuDeviceGetLimits(_sg.wgpu.dev, &_sg.wgpu.limits); - - const WGPULimits* l = &_sg.wgpu.limits.limits; - _sg.limits.max_image_size_2d = (int) l->maxTextureDimension2D; - _sg.limits.max_image_size_cube = (int) l->maxTextureDimension2D; // not a bug, see: https://github.com/gpuweb/gpuweb/issues/1327 - _sg.limits.max_image_size_3d = (int) l->maxTextureDimension3D; - _sg.limits.max_image_size_array = (int) l->maxTextureDimension2D; - _sg.limits.max_image_array_layers = (int) l->maxTextureArrayLayers; - _sg.limits.max_vertex_attrs = SG_MAX_VERTEX_ATTRIBUTES; - - // NOTE: no WGPUTextureFormat_R16Unorm - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_SRGB8A8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_BGRA8]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16F]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16F]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); - _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGB10A2]); - - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8SN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG8SN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA8SN]); - - // FIXME: can be made renderable via extension - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG11B10F]); - - // NOTE: msaa rendering is possible in WebGPU, but no resolve - // which is a combination that's not currently supported in sokol-gfx - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R8UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R8SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG8UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG8SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA8UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA8SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R16UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R16SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG16UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG16SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA16UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA16SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32SI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); - - if (wgpuDeviceHasFeature(_sg.wgpu.dev, WGPUFeatureName_Float32Filterable)) { - _sg_pixelformat_sfr(&_sg.formats[SG_PIXELFORMAT_R32F]); - _sg_pixelformat_sfr(&_sg.formats[SG_PIXELFORMAT_RG32F]); - _sg_pixelformat_sfr(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); - } else { - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32F]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32F]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); - } - - _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH]); - _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL]); - - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGB9E5]); - - if (wgpuDeviceHasFeature(_sg.wgpu.dev, WGPUFeatureName_TextureCompressionBC)) { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC1_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC2_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_SRGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_R]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_RSN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RG]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RGSN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBF]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBUF]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_SRGBA]); - } - if (wgpuDeviceHasFeature(_sg.wgpu.dev, WGPUFeatureName_TextureCompressionETC2)) { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8A8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11SN]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11SN]); - } - - if (wgpuDeviceHasFeature(_sg.wgpu.dev, WGPUFeatureName_TextureCompressionASTC)) { - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_RGBA]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_SRGBA]); - } -} - -_SOKOL_PRIVATE void _sg_wgpu_uniform_buffer_init(const sg_desc* desc) { - SOKOL_ASSERT(0 == _sg.wgpu.uniform.staging); - SOKOL_ASSERT(0 == _sg.wgpu.uniform.buf); - SOKOL_ASSERT(0 == _sg.wgpu.uniform.bind.group_layout); - SOKOL_ASSERT(0 == _sg.wgpu.uniform.bind.group); - - // Add the max-uniform-update size (64 KB) to the requested buffer size, - // this is to prevent validation errors in the WebGPU implementation - // if the entire buffer size is used per frame. 64 KB is the allowed - // max uniform update size on NVIDIA - // - // FIXME: is this still needed? - _sg.wgpu.uniform.num_bytes = (uint32_t)(desc->uniform_buffer_size + _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE); - _sg.wgpu.uniform.staging = (uint8_t*)_sg_malloc(_sg.wgpu.uniform.num_bytes); - - WGPUBufferDescriptor ub_desc; - _sg_clear(&ub_desc, sizeof(ub_desc)); - ub_desc.size = _sg.wgpu.uniform.num_bytes; - ub_desc.usage = WGPUBufferUsage_Uniform|WGPUBufferUsage_CopyDst; - _sg.wgpu.uniform.buf = wgpuDeviceCreateBuffer(_sg.wgpu.dev, &ub_desc); - SOKOL_ASSERT(_sg.wgpu.uniform.buf); - - WGPUBindGroupLayoutEntry ub_bgle_desc[SG_NUM_SHADER_STAGES][SG_MAX_SHADERSTAGE_UBS]; - _sg_clear(ub_bgle_desc, sizeof(ub_bgle_desc)); - for (uint32_t stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - WGPUShaderStage vis = (stage_index == SG_SHADERSTAGE_VS) ? WGPUShaderStage_Vertex : WGPUShaderStage_Fragment; - for (uint32_t ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { - uint32_t bind_index = stage_index * SG_MAX_SHADERSTAGE_UBS + ub_index; - ub_bgle_desc[stage_index][ub_index].binding = bind_index; - ub_bgle_desc[stage_index][ub_index].visibility = vis; - ub_bgle_desc[stage_index][ub_index].buffer.type = WGPUBufferBindingType_Uniform; - ub_bgle_desc[stage_index][ub_index].buffer.hasDynamicOffset = true; - } - } - - WGPUBindGroupLayoutDescriptor ub_bgl_desc; - _sg_clear(&ub_bgl_desc, sizeof(ub_bgl_desc)); - ub_bgl_desc.entryCount = SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_UBS; - ub_bgl_desc.entries = &ub_bgle_desc[0][0]; - _sg.wgpu.uniform.bind.group_layout = wgpuDeviceCreateBindGroupLayout(_sg.wgpu.dev, &ub_bgl_desc); - SOKOL_ASSERT(_sg.wgpu.uniform.bind.group_layout); - - WGPUBindGroupEntry ub_bge[SG_NUM_SHADER_STAGES][SG_MAX_SHADERSTAGE_UBS]; - _sg_clear(ub_bge, sizeof(ub_bge)); - for (uint32_t stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - for (uint32_t ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { - uint32_t bind_index = stage_index * SG_MAX_SHADERSTAGE_UBS + ub_index; - ub_bge[stage_index][ub_index].binding = bind_index; - ub_bge[stage_index][ub_index].buffer = _sg.wgpu.uniform.buf; - ub_bge[stage_index][ub_index].size = _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE; - } - } - WGPUBindGroupDescriptor bg_desc; - _sg_clear(&bg_desc, sizeof(bg_desc)); - bg_desc.layout = _sg.wgpu.uniform.bind.group_layout; - bg_desc.entryCount = SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_UBS; - bg_desc.entries = &ub_bge[0][0]; - _sg.wgpu.uniform.bind.group = wgpuDeviceCreateBindGroup(_sg.wgpu.dev, &bg_desc); - SOKOL_ASSERT(_sg.wgpu.uniform.bind.group); -} - -_SOKOL_PRIVATE void _sg_wgpu_uniform_buffer_discard(void) { - if (_sg.wgpu.uniform.buf) { - wgpuBufferRelease(_sg.wgpu.uniform.buf); - _sg.wgpu.uniform.buf = 0; - } - if (_sg.wgpu.uniform.bind.group) { - wgpuBindGroupRelease(_sg.wgpu.uniform.bind.group); - _sg.wgpu.uniform.bind.group = 0; - } - if (_sg.wgpu.uniform.bind.group_layout) { - wgpuBindGroupLayoutRelease(_sg.wgpu.uniform.bind.group_layout); - _sg.wgpu.uniform.bind.group_layout = 0; - } - if (_sg.wgpu.uniform.staging) { - _sg_free(_sg.wgpu.uniform.staging); - _sg.wgpu.uniform.staging = 0; - } -} - -_SOKOL_PRIVATE void _sg_wgpu_uniform_buffer_on_begin_pass(void) { - wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, - 0, // groupIndex 0 is reserved for uniform buffers - _sg.wgpu.uniform.bind.group, - SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_UBS, - &_sg.wgpu.uniform.bind.offsets[0][0]); -} - -_SOKOL_PRIVATE void _sg_wgpu_uniform_buffer_on_commit(void) { - wgpuQueueWriteBuffer(_sg.wgpu.queue, _sg.wgpu.uniform.buf, 0, _sg.wgpu.uniform.staging, _sg.wgpu.uniform.offset); - _sg_stats_add(wgpu.uniforms.size_write_buffer, _sg.wgpu.uniform.offset); - _sg.wgpu.uniform.offset = 0; - _sg_clear(&_sg.wgpu.uniform.bind.offsets[0][0], sizeof(_sg.wgpu.uniform.bind.offsets)); -} - -_SOKOL_PRIVATE void _sg_wgpu_bindgroups_pool_init(const sg_desc* desc) { - SOKOL_ASSERT((desc->wgpu_bindgroups_cache_size > 0) && (desc->wgpu_bindgroups_cache_size < _SG_MAX_POOL_SIZE)); - _sg_wgpu_bindgroups_pool_t* p = &_sg.wgpu.bindgroups_pool; - SOKOL_ASSERT(0 == p->bindgroups); - const int pool_size = desc->wgpu_bindgroups_cache_size; - _sg_init_pool(&p->pool, pool_size); - size_t pool_byte_size = sizeof(_sg_wgpu_bindgroup_t) * (size_t)p->pool.size; - p->bindgroups = (_sg_wgpu_bindgroup_t*) _sg_malloc_clear(pool_byte_size); -} - -_SOKOL_PRIVATE void _sg_wgpu_bindgroups_pool_discard(void) { - _sg_wgpu_bindgroups_pool_t* p = &_sg.wgpu.bindgroups_pool; - SOKOL_ASSERT(p->bindgroups); - _sg_free(p->bindgroups); p->bindgroups = 0; - _sg_discard_pool(&p->pool); -} - -_SOKOL_PRIVATE _sg_wgpu_bindgroup_t* _sg_wgpu_bindgroup_at(uint32_t bg_id) { - SOKOL_ASSERT(SG_INVALID_ID != bg_id); - _sg_wgpu_bindgroups_pool_t* p = &_sg.wgpu.bindgroups_pool; - int slot_index = _sg_slot_index(bg_id); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->bindgroups[slot_index]; -} - -_SOKOL_PRIVATE _sg_wgpu_bindgroup_t* _sg_wgpu_lookup_bindgroup(uint32_t bg_id) { - if (SG_INVALID_ID != bg_id) { - _sg_wgpu_bindgroup_t* bg = _sg_wgpu_bindgroup_at(bg_id); - if (bg->slot.id == bg_id) { - return bg; - } - } - return 0; -} - -_SOKOL_PRIVATE _sg_wgpu_bindgroup_handle_t _sg_wgpu_alloc_bindgroup(void) { - _sg_wgpu_bindgroups_pool_t* p = &_sg.wgpu.bindgroups_pool; - _sg_wgpu_bindgroup_handle_t res; - int slot_index = _sg_pool_alloc_index(&p->pool); - if (_SG_INVALID_SLOT_INDEX != slot_index) { - res.id = _sg_slot_alloc(&p->pool, &p->bindgroups[slot_index].slot, slot_index); - } else { - res.id = SG_INVALID_ID; - _SG_ERROR(WGPU_BINDGROUPS_POOL_EXHAUSTED); - } - return res; -} - -_SOKOL_PRIVATE void _sg_wgpu_dealloc_bindgroup(_sg_wgpu_bindgroup_t* bg) { - SOKOL_ASSERT(bg && (bg->slot.state == SG_RESOURCESTATE_ALLOC) && (bg->slot.id != SG_INVALID_ID)); - _sg_wgpu_bindgroups_pool_t* p = &_sg.wgpu.bindgroups_pool; - _sg_pool_free_index(&p->pool, _sg_slot_index(bg->slot.id)); - _sg_reset_slot(&bg->slot); -} - -_SOKOL_PRIVATE void _sg_wgpu_reset_bindgroup_to_alloc_state(_sg_wgpu_bindgroup_t* bg) { - SOKOL_ASSERT(bg); - _sg_slot_t slot = bg->slot; - _sg_clear(bg, sizeof(_sg_wgpu_bindgroup_t)); - bg->slot = slot; - bg->slot.state = SG_RESOURCESTATE_ALLOC; -} - -// MurmurHash64B (see: https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L142) -_SOKOL_PRIVATE uint64_t _sg_wgpu_hash(const void* key, int len, uint64_t seed) { - const uint32_t m = 0x5bd1e995; - const int r = 24; - uint32_t h1 = (uint32_t)seed ^ (uint32_t)len; - uint32_t h2 = (uint32_t)(seed >> 32); - const uint32_t * data = (const uint32_t *)key; - while (len >= 8) { - uint32_t k1 = *data++; - k1 *= m; k1 ^= k1 >> r; k1 *= m; - h1 *= m; h1 ^= k1; - len -= 4; - uint32_t k2 = *data++; - k2 *= m; k2 ^= k2 >> r; k2 *= m; - h2 *= m; h2 ^= k2; - len -= 4; - } - if (len >= 4) { - uint32_t k1 = *data++; - k1 *= m; k1 ^= k1 >> r; k1 *= m; - h1 *= m; h1 ^= k1; - len -= 4; - } - switch(len) { - case 3: h2 ^= (uint32_t)(((unsigned char*)data)[2] << 16); - case 2: h2 ^= (uint32_t)(((unsigned char*)data)[1] << 8); - case 1: h2 ^= ((unsigned char*)data)[0]; - h2 *= m; - }; - h1 ^= h2 >> 18; h1 *= m; - h2 ^= h1 >> 22; h2 *= m; - h1 ^= h2 >> 17; h1 *= m; - h2 ^= h1 >> 19; h2 *= m; - uint64_t h = h1; - h = (h << 32) | h2; - return h; -} - -_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_item(_sg_wgpu_bindgroups_cache_item_type_t type, uint32_t id) { - return (((uint64_t)type) << 32) | id; -} - -_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_pip_item(uint32_t id) { - return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_PIPELINE, id); -} - -_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_image_item(uint32_t id) { - return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_IMAGE, id); -} - -_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_sampler_item(uint32_t id) { - return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_SAMPLER, id); -} - -_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_sbuf_item(uint32_t id) { - return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_STORAGEBUFFER, id); -} - -_SOKOL_PRIVATE void _sg_wgpu_init_bindgroups_cache_key(_sg_wgpu_bindgroups_cache_key_t* key, const _sg_bindings_t* bnd) { - SOKOL_ASSERT(bnd); - SOKOL_ASSERT(bnd->pip); - SOKOL_ASSERT(bnd->num_vs_imgs <= SG_MAX_SHADERSTAGE_IMAGES); - SOKOL_ASSERT(bnd->num_vs_smps <= SG_MAX_SHADERSTAGE_SAMPLERS); - SOKOL_ASSERT(bnd->num_vs_sbufs <= SG_MAX_SHADERSTAGE_STORAGEBUFFERS); - SOKOL_ASSERT(bnd->num_fs_imgs <= SG_MAX_SHADERSTAGE_IMAGES); - SOKOL_ASSERT(bnd->num_fs_smps <= SG_MAX_SHADERSTAGE_SAMPLERS); - SOKOL_ASSERT(bnd->num_fs_sbufs <= SG_MAX_SHADERSTAGE_STORAGEBUFFERS); - - _sg_clear(key->items, sizeof(key->items)); - int item_idx = 0; - key->items[item_idx++] = _sg_wgpu_bindgroups_cache_pip_item(bnd->pip->slot.id); - for (int i = 0; i < bnd->num_vs_imgs; i++) { - SOKOL_ASSERT(bnd->vs_imgs[i]); - SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); - key->items[item_idx++] = _sg_wgpu_bindgroups_cache_image_item(bnd->vs_imgs[i]->slot.id); - } - for (int i = 0; i < bnd->num_vs_smps; i++) { - SOKOL_ASSERT(bnd->vs_smps[i]); - SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); - key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sampler_item(bnd->vs_smps[i]->slot.id); - } - for (int i = 0; i < bnd->num_vs_sbufs; i++) { - SOKOL_ASSERT(bnd->vs_sbufs[i]); - SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); - key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sbuf_item(bnd->vs_sbufs[i]->slot.id); - } - for (int i = 0; i < bnd->num_fs_imgs; i++) { - SOKOL_ASSERT(bnd->fs_imgs[i]); - SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); - key->items[item_idx++] = _sg_wgpu_bindgroups_cache_image_item(bnd->fs_imgs[i]->slot.id); - } - for (int i = 0; i < bnd->num_fs_smps; i++) { - SOKOL_ASSERT(bnd->fs_smps[i]); - SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); - key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sampler_item(bnd->fs_smps[i]->slot.id); - } - for (int i = 0; i < bnd->num_fs_sbufs; i++) { - SOKOL_ASSERT(bnd->fs_sbufs[i]); - SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); - key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sbuf_item(bnd->fs_sbufs[i]->slot.id); - } - SOKOL_ASSERT(item_idx == (1 + bnd->num_vs_imgs + bnd->num_vs_smps + bnd->num_vs_sbufs + bnd->num_fs_imgs + bnd->num_fs_smps + bnd->num_fs_sbufs)); - key->hash = _sg_wgpu_hash(&key->items, (int)sizeof(key->items), 0x1234567887654321); -} - -_SOKOL_PRIVATE bool _sg_wgpu_compare_bindgroups_cache_key(_sg_wgpu_bindgroups_cache_key_t* k0, _sg_wgpu_bindgroups_cache_key_t* k1) { - SOKOL_ASSERT(k0 && k1); - if (k0->hash != k1->hash) { - return false; - } - if (memcmp(&k0->items, &k1->items, sizeof(k0->items)) != 0) { - _sg_stats_add(wgpu.bindings.num_bindgroup_cache_hash_vs_key_mismatch, 1); - return false; - } - return true; -} - -_SOKOL_PRIVATE _sg_wgpu_bindgroup_t* _sg_wgpu_create_bindgroup(_sg_bindings_t* bnd) { - SOKOL_ASSERT(_sg.wgpu.dev); - SOKOL_ASSERT(bnd->pip); - SOKOL_ASSERT(bnd->pip->shader && (bnd->pip->cmn.shader_id.id == bnd->pip->shader->slot.id)); - _sg_stats_add(wgpu.bindings.num_create_bindgroup, 1); - _sg_wgpu_bindgroup_handle_t bg_id = _sg_wgpu_alloc_bindgroup(); - if (bg_id.id == SG_INVALID_ID) { - return 0; - } - _sg_wgpu_bindgroup_t* bg = _sg_wgpu_bindgroup_at(bg_id.id); - SOKOL_ASSERT(bg && (bg->slot.state == SG_RESOURCESTATE_ALLOC)); - - // create wgpu bindgroup object - WGPUBindGroupLayout bgl = bnd->pip->shader->wgpu.bind_group_layout; - SOKOL_ASSERT(bgl); - WGPUBindGroupEntry wgpu_entries[_SG_WGPU_MAX_BINDGROUP_ENTRIES]; - _sg_clear(&wgpu_entries, sizeof(wgpu_entries)); - int bge_index = 0; - for (int i = 0; i < bnd->num_vs_imgs; i++) { - WGPUBindGroupEntry* wgpu_entry = &wgpu_entries[bge_index++]; - wgpu_entry->binding = _sg_wgpu_image_binding(SG_SHADERSTAGE_VS, i); - wgpu_entry->textureView = bnd->vs_imgs[i]->wgpu.view; - } - for (int i = 0; i < bnd->num_vs_smps; i++) { - WGPUBindGroupEntry* wgpu_entry = &wgpu_entries[bge_index++]; - wgpu_entry->binding = _sg_wgpu_sampler_binding(SG_SHADERSTAGE_VS, i); - wgpu_entry->sampler = bnd->vs_smps[i]->wgpu.smp; - } - for (int i = 0; i < bnd->num_vs_sbufs; i++) { - WGPUBindGroupEntry* wgpu_entry = &wgpu_entries[bge_index++]; - wgpu_entry->binding = _sg_wgpu_storagebuffer_binding(SG_SHADERSTAGE_VS, i); - wgpu_entry->buffer = bnd->vs_sbufs[i]->wgpu.buf; - wgpu_entry->size = (uint64_t) bnd->vs_sbufs[i]->cmn.size; - } - for (int i = 0; i < bnd->num_fs_imgs; i++) { - WGPUBindGroupEntry* wgpu_entry = &wgpu_entries[bge_index++]; - wgpu_entry->binding = _sg_wgpu_image_binding(SG_SHADERSTAGE_FS, i); - wgpu_entry->textureView = bnd->fs_imgs[i]->wgpu.view; - } - for (int i = 0; i < bnd->num_fs_smps; i++) { - WGPUBindGroupEntry* wgpu_entry = &wgpu_entries[bge_index++]; - wgpu_entry->binding = _sg_wgpu_sampler_binding(SG_SHADERSTAGE_FS, i); - wgpu_entry->sampler = bnd->fs_smps[i]->wgpu.smp; - } - for (int i = 0; i < bnd->num_fs_sbufs; i++) { - WGPUBindGroupEntry* wgpu_entry = &wgpu_entries[bge_index++]; - wgpu_entry->binding = _sg_wgpu_storagebuffer_binding(SG_SHADERSTAGE_FS, i); - wgpu_entry->buffer = bnd->fs_sbufs[i]->wgpu.buf; - wgpu_entry->size = (uint64_t) bnd->fs_sbufs[i]->cmn.size; - } - WGPUBindGroupDescriptor bg_desc; - _sg_clear(&bg_desc, sizeof(bg_desc)); - bg_desc.layout = bgl; - bg_desc.entryCount = (size_t)bge_index; - bg_desc.entries = &wgpu_entries[0]; - bg->bindgroup = wgpuDeviceCreateBindGroup(_sg.wgpu.dev, &bg_desc); - if (bg->bindgroup == 0) { - _SG_ERROR(WGPU_CREATEBINDGROUP_FAILED); - bg->slot.state = SG_RESOURCESTATE_FAILED; - return bg; - } - - _sg_wgpu_init_bindgroups_cache_key(&bg->key, bnd); - - bg->slot.state = SG_RESOURCESTATE_VALID; - return bg; -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_bindgroup(_sg_wgpu_bindgroup_t* bg) { - SOKOL_ASSERT(bg); - _sg_stats_add(wgpu.bindings.num_discard_bindgroup, 1); - if (bg->slot.state == SG_RESOURCESTATE_VALID) { - if (bg->bindgroup) { - wgpuBindGroupRelease(bg->bindgroup); - bg->bindgroup = 0; - } - _sg_wgpu_reset_bindgroup_to_alloc_state(bg); - SOKOL_ASSERT(bg->slot.state == SG_RESOURCESTATE_ALLOC); - } - if (bg->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_wgpu_dealloc_bindgroup(bg); - SOKOL_ASSERT(bg->slot.state == SG_RESOURCESTATE_INITIAL); - } -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_all_bindgroups(void) { - _sg_wgpu_bindgroups_pool_t* p = &_sg.wgpu.bindgroups_pool; - for (int i = 0; i < p->pool.size; i++) { - sg_resource_state state = p->bindgroups[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_wgpu_discard_bindgroup(&p->bindgroups[i]); - } - } -} - -_SOKOL_PRIVATE void _sg_wgpu_bindgroups_cache_init(const sg_desc* desc) { - SOKOL_ASSERT(desc); - SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.num == 0); - SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.index_mask == 0); - SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.items == 0); - const int num = desc->wgpu_bindgroups_cache_size; - if (num <= 1) { - _SG_PANIC(WGPU_BINDGROUPSCACHE_SIZE_GREATER_ONE); - } - if (!_sg_ispow2(num)) { - _SG_PANIC(WGPU_BINDGROUPSCACHE_SIZE_POW2); - } - _sg.wgpu.bindgroups_cache.num = (uint32_t)desc->wgpu_bindgroups_cache_size; - _sg.wgpu.bindgroups_cache.index_mask = _sg.wgpu.bindgroups_cache.num - 1; - size_t size_in_bytes = sizeof(_sg_wgpu_bindgroup_handle_t) * (size_t)num; - _sg.wgpu.bindgroups_cache.items = (_sg_wgpu_bindgroup_handle_t*)_sg_malloc_clear(size_in_bytes); -} - -_SOKOL_PRIVATE void _sg_wgpu_bindgroups_cache_discard(void) { - if (_sg.wgpu.bindgroups_cache.items) { - _sg_free(_sg.wgpu.bindgroups_cache.items); - _sg.wgpu.bindgroups_cache.items = 0; - } - _sg.wgpu.bindgroups_cache.num = 0; - _sg.wgpu.bindgroups_cache.index_mask = 0; -} - -_SOKOL_PRIVATE void _sg_wgpu_bindgroups_cache_set(uint64_t hash, uint32_t bg_id) { - uint32_t index = hash & _sg.wgpu.bindgroups_cache.index_mask; - SOKOL_ASSERT(index < _sg.wgpu.bindgroups_cache.num); - SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.items); - _sg.wgpu.bindgroups_cache.items[index].id = bg_id; -} - -_SOKOL_PRIVATE uint32_t _sg_wgpu_bindgroups_cache_get(uint64_t hash) { - uint32_t index = hash & _sg.wgpu.bindgroups_cache.index_mask; - SOKOL_ASSERT(index < _sg.wgpu.bindgroups_cache.num); - SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.items); - return _sg.wgpu.bindgroups_cache.items[index].id; -} - -// called from wgpu resource destroy functions to also invalidate any -// bindgroups cache slot and bindgroup referencing that resource -_SOKOL_PRIVATE void _sg_wgpu_bindgroups_cache_invalidate(_sg_wgpu_bindgroups_cache_item_type_t type, uint32_t id) { - const uint64_t key_item = _sg_wgpu_bindgroups_cache_item(type, id); - SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.items); - for (uint32_t cache_item_idx = 0; cache_item_idx < _sg.wgpu.bindgroups_cache.num; cache_item_idx++) { - const uint32_t bg_id = _sg.wgpu.bindgroups_cache.items[cache_item_idx].id; - if (bg_id != SG_INVALID_ID) { - _sg_wgpu_bindgroup_t* bg = _sg_wgpu_lookup_bindgroup(bg_id); - SOKOL_ASSERT(bg && (bg->slot.state == SG_RESOURCESTATE_VALID)); - // check if resource is in bindgroup, if yes discard bindgroup and invalidate cache slot - bool invalidate_cache_item = false; - for (int key_item_idx = 0; key_item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS; key_item_idx++) { - if (bg->key.items[key_item_idx] == key_item) { - invalidate_cache_item = true; - break; - } - } - if (invalidate_cache_item) { - _sg_wgpu_discard_bindgroup(bg); bg = 0; - _sg_wgpu_bindgroups_cache_set(cache_item_idx, SG_INVALID_ID); - _sg_stats_add(wgpu.bindings.num_bindgroup_cache_invalidates, 1); - } - } - } -} - -_SOKOL_PRIVATE void _sg_wgpu_bindings_cache_clear(void) { - memset(&_sg.wgpu.bindings_cache, 0, sizeof(_sg.wgpu.bindings_cache)); -} - -_SOKOL_PRIVATE bool _sg_wgpu_bindings_cache_vb_dirty(int index, const _sg_buffer_t* vb, int offset) { - SOKOL_ASSERT((index >= 0) && (index < SG_MAX_VERTEX_BUFFERS)); - if (vb) { - return (_sg.wgpu.bindings_cache.vbs[index].buffer.id != vb->slot.id) - || (_sg.wgpu.bindings_cache.vbs[index].offset != offset); - } else { - return _sg.wgpu.bindings_cache.vbs[index].buffer.id != SG_INVALID_ID; - } -} - -_SOKOL_PRIVATE void _sg_wgpu_bindings_cache_vb_update(int index, const _sg_buffer_t* vb, int offset) { - SOKOL_ASSERT((index >= 0) && (index < SG_MAX_VERTEX_BUFFERS)); - if (vb) { - _sg.wgpu.bindings_cache.vbs[index].buffer.id = vb->slot.id; - _sg.wgpu.bindings_cache.vbs[index].offset = offset; - } else { - _sg.wgpu.bindings_cache.vbs[index].buffer.id = SG_INVALID_ID; - _sg.wgpu.bindings_cache.vbs[index].offset = 0; - } -} - -_SOKOL_PRIVATE bool _sg_wgpu_bindings_cache_ib_dirty(const _sg_buffer_t* ib, int offset) { - if (ib) { - return (_sg.wgpu.bindings_cache.ib.buffer.id != ib->slot.id) - || (_sg.wgpu.bindings_cache.ib.offset != offset); - } else { - return _sg.wgpu.bindings_cache.ib.buffer.id != SG_INVALID_ID; - } -} - -_SOKOL_PRIVATE void _sg_wgpu_bindings_cache_ib_update(const _sg_buffer_t* ib, int offset) { - if (ib) { - _sg.wgpu.bindings_cache.ib.buffer.id = ib->slot.id; - _sg.wgpu.bindings_cache.ib.offset = offset; - } else { - _sg.wgpu.bindings_cache.ib.buffer.id = SG_INVALID_ID; - _sg.wgpu.bindings_cache.ib.offset = 0; - } -} - -_SOKOL_PRIVATE bool _sg_wgpu_bindings_cache_bg_dirty(const _sg_wgpu_bindgroup_t* bg) { - if (bg) { - return _sg.wgpu.bindings_cache.bg.id != bg->slot.id; - } else { - return _sg.wgpu.bindings_cache.bg.id != SG_INVALID_ID; - } -} - -_SOKOL_PRIVATE void _sg_wgpu_bindings_cache_bg_update(const _sg_wgpu_bindgroup_t* bg) { - if (bg) { - _sg.wgpu.bindings_cache.bg.id = bg->slot.id; - } else { - _sg.wgpu.bindings_cache.bg.id = SG_INVALID_ID; - } -} - -_SOKOL_PRIVATE void _sg_wgpu_set_bindgroup(_sg_wgpu_bindgroup_t* bg) { - if (_sg_wgpu_bindings_cache_bg_dirty(bg)) { - _sg_wgpu_bindings_cache_bg_update(bg); - _sg_stats_add(wgpu.bindings.num_set_bindgroup, 1); - if (bg) { - SOKOL_ASSERT(bg->slot.state == SG_RESOURCESTATE_VALID); - SOKOL_ASSERT(bg->bindgroup); - wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, _SG_WGPU_IMAGE_SAMPLER_BINDGROUP_INDEX, bg->bindgroup, 0, 0); - } else { - // a nullptr bindgroup means setting the empty bindgroup - wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, _SG_WGPU_IMAGE_SAMPLER_BINDGROUP_INDEX, _sg.wgpu.empty_bind_group, 0, 0); - } - } else { - _sg_stats_add(wgpu.bindings.num_skip_redundant_bindgroup, 1); - } -} - -_SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) { - if ((bnd->num_vs_imgs + bnd->num_vs_smps + bnd->num_vs_sbufs + bnd->num_fs_imgs + bnd->num_fs_smps + bnd->num_fs_sbufs) > 0) { - if (!_sg.desc.wgpu_disable_bindgroups_cache) { - _sg_wgpu_bindgroup_t* bg = 0; - _sg_wgpu_bindgroups_cache_key_t key; - _sg_wgpu_init_bindgroups_cache_key(&key, bnd); - uint32_t bg_id = _sg_wgpu_bindgroups_cache_get(key.hash); - if (bg_id != SG_INVALID_ID) { - // potential cache hit - bg = _sg_wgpu_lookup_bindgroup(bg_id); - SOKOL_ASSERT(bg && (bg->slot.state == SG_RESOURCESTATE_VALID)); - if (!_sg_wgpu_compare_bindgroups_cache_key(&key, &bg->key)) { - // cache collision, need to delete cached bindgroup - _sg_stats_add(wgpu.bindings.num_bindgroup_cache_collisions, 1); - _sg_wgpu_discard_bindgroup(bg); - _sg_wgpu_bindgroups_cache_set(key.hash, SG_INVALID_ID); - bg = 0; - } else { - _sg_stats_add(wgpu.bindings.num_bindgroup_cache_hits, 1); - } - } else { - _sg_stats_add(wgpu.bindings.num_bindgroup_cache_misses, 1); - } - if (bg == 0) { - // either no cache entry yet, or cache collision, create new bindgroup and store in cache - bg = _sg_wgpu_create_bindgroup(bnd); - _sg_wgpu_bindgroups_cache_set(key.hash, bg->slot.id); - } - if (bg && bg->slot.state == SG_RESOURCESTATE_VALID) { - _sg_wgpu_set_bindgroup(bg); - } else { - return false; - } - } else { - // bindgroups cache disabled, create and destroy bindgroup on the fly (expensive!) - _sg_wgpu_bindgroup_t* bg = _sg_wgpu_create_bindgroup(bnd); - if (bg) { - if (bg->slot.state == SG_RESOURCESTATE_VALID) { - _sg_wgpu_set_bindgroup(bg); - } - _sg_wgpu_discard_bindgroup(bg); - } else { - return false; - } - } - } else { - _sg_wgpu_set_bindgroup(0); - } - return true; -} - -_SOKOL_PRIVATE bool _sg_wgpu_apply_index_buffer(_sg_bindings_t* bnd) { - if (_sg_wgpu_bindings_cache_ib_dirty(bnd->ib, bnd->ib_offset)) { - _sg_wgpu_bindings_cache_ib_update(bnd->ib, bnd->ib_offset); - if (bnd->ib) { - const WGPUIndexFormat format = _sg_wgpu_indexformat(bnd->pip->cmn.index_type); - const uint64_t buf_size = (uint64_t)bnd->ib->cmn.size; - const uint64_t offset = (uint64_t)bnd->ib_offset; - SOKOL_ASSERT(buf_size > offset); - const uint64_t max_bytes = buf_size - offset; - wgpuRenderPassEncoderSetIndexBuffer(_sg.wgpu.pass_enc, bnd->ib->wgpu.buf, format, offset, max_bytes); - _sg_stats_add(wgpu.bindings.num_set_index_buffer, 1); - } - // FIXME: else-path should actually set a null index buffer (this was just recently implemented in WebGPU) - } else { - _sg_stats_add(wgpu.bindings.num_skip_redundant_index_buffer, 1); - } - return true; -} - -_SOKOL_PRIVATE bool _sg_wgpu_apply_vertex_buffers(_sg_bindings_t* bnd) { - for (int slot = 0; slot < bnd->num_vbs; slot++) { - if (_sg_wgpu_bindings_cache_vb_dirty(slot, bnd->vbs[slot], bnd->vb_offsets[slot])) { - _sg_wgpu_bindings_cache_vb_update(slot, bnd->vbs[slot], bnd->vb_offsets[slot]); - const uint64_t buf_size = (uint64_t)bnd->vbs[slot]->cmn.size; - const uint64_t offset = (uint64_t)bnd->vb_offsets[slot]; - SOKOL_ASSERT(buf_size > offset); - const uint64_t max_bytes = buf_size - offset; - wgpuRenderPassEncoderSetVertexBuffer(_sg.wgpu.pass_enc, (uint32_t)slot, bnd->vbs[slot]->wgpu.buf, offset, max_bytes); - _sg_stats_add(wgpu.bindings.num_set_vertex_buffer, 1); - } else { - _sg_stats_add(wgpu.bindings.num_skip_redundant_vertex_buffer, 1); - } - } - // FIXME: remaining vb slots should actually set a null vertex buffer (this was just recently implemented in WebGPU) - return true; -} - -_SOKOL_PRIVATE void _sg_wgpu_setup_backend(const sg_desc* desc) { - SOKOL_ASSERT(desc); - SOKOL_ASSERT(desc->environment.wgpu.device); - SOKOL_ASSERT(desc->uniform_buffer_size > 0); - _sg.backend = SG_BACKEND_WGPU; - _sg.wgpu.valid = true; - _sg.wgpu.dev = (WGPUDevice) desc->environment.wgpu.device; - _sg.wgpu.queue = wgpuDeviceGetQueue(_sg.wgpu.dev); - SOKOL_ASSERT(_sg.wgpu.queue); - - _sg_wgpu_init_caps(); - _sg_wgpu_uniform_buffer_init(desc); - _sg_wgpu_bindgroups_pool_init(desc); - _sg_wgpu_bindgroups_cache_init(desc); - _sg_wgpu_bindings_cache_clear(); - - // create an empty bind group for shader stages without bound images - // FIXME: once WebGPU supports setting null objects, this can be removed - WGPUBindGroupLayoutDescriptor bgl_desc; - _sg_clear(&bgl_desc, sizeof(bgl_desc)); - WGPUBindGroupLayout empty_bgl = wgpuDeviceCreateBindGroupLayout(_sg.wgpu.dev, &bgl_desc); - SOKOL_ASSERT(empty_bgl); - WGPUBindGroupDescriptor bg_desc; - _sg_clear(&bg_desc, sizeof(bg_desc)); - bg_desc.layout = empty_bgl; - _sg.wgpu.empty_bind_group = wgpuDeviceCreateBindGroup(_sg.wgpu.dev, &bg_desc); - SOKOL_ASSERT(_sg.wgpu.empty_bind_group); - wgpuBindGroupLayoutRelease(empty_bgl); - - // create initial per-frame command encoder - WGPUCommandEncoderDescriptor cmd_enc_desc; - _sg_clear(&cmd_enc_desc, sizeof(cmd_enc_desc)); - _sg.wgpu.cmd_enc = wgpuDeviceCreateCommandEncoder(_sg.wgpu.dev, &cmd_enc_desc); - SOKOL_ASSERT(_sg.wgpu.cmd_enc); -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_backend(void) { - SOKOL_ASSERT(_sg.wgpu.valid); - SOKOL_ASSERT(_sg.wgpu.cmd_enc); - _sg.wgpu.valid = false; - _sg_wgpu_discard_all_bindgroups(); - _sg_wgpu_bindgroups_cache_discard(); - _sg_wgpu_bindgroups_pool_discard(); - _sg_wgpu_uniform_buffer_discard(); - wgpuBindGroupRelease(_sg.wgpu.empty_bind_group); _sg.wgpu.empty_bind_group = 0; - wgpuCommandEncoderRelease(_sg.wgpu.cmd_enc); _sg.wgpu.cmd_enc = 0; - wgpuQueueRelease(_sg.wgpu.queue); _sg.wgpu.queue = 0; -} - -_SOKOL_PRIVATE void _sg_wgpu_reset_state_cache(void) { - _sg_wgpu_bindings_cache_clear(); -} - -_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { - SOKOL_ASSERT(buf && desc); - const bool injected = (0 != desc->wgpu_buffer); - if (injected) { - buf->wgpu.buf = (WGPUBuffer) desc->wgpu_buffer; - wgpuBufferReference(buf->wgpu.buf); - } else { - // buffer mapping size must be multiple of 4, so round up buffer size (only a problem - // with index buffers containing odd number of indices) - const uint64_t wgpu_buf_size = _sg_roundup_u64((uint64_t)buf->cmn.size, 4); - const bool map_at_creation = (SG_USAGE_IMMUTABLE == buf->cmn.usage); - - WGPUBufferDescriptor wgpu_buf_desc; - _sg_clear(&wgpu_buf_desc, sizeof(wgpu_buf_desc)); - wgpu_buf_desc.usage = _sg_wgpu_buffer_usage(buf->cmn.type, buf->cmn.usage); - wgpu_buf_desc.size = wgpu_buf_size; - wgpu_buf_desc.mappedAtCreation = map_at_creation; - wgpu_buf_desc.label = desc->label; - buf->wgpu.buf = wgpuDeviceCreateBuffer(_sg.wgpu.dev, &wgpu_buf_desc); - if (0 == buf->wgpu.buf) { - _SG_ERROR(WGPU_CREATE_BUFFER_FAILED); - return SG_RESOURCESTATE_FAILED; - } - if (map_at_creation) { - SOKOL_ASSERT(desc->data.ptr && (desc->data.size > 0)); - SOKOL_ASSERT(desc->data.size <= (size_t)buf->cmn.size); - // FIXME: inefficient on WASM - void* ptr = wgpuBufferGetMappedRange(buf->wgpu.buf, 0, wgpu_buf_size); - SOKOL_ASSERT(ptr); - memcpy(ptr, desc->data.ptr, desc->data.size); - wgpuBufferUnmap(buf->wgpu.buf); - } - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_buffer(_sg_buffer_t* buf) { - SOKOL_ASSERT(buf); - if (buf->cmn.type == SG_BUFFERTYPE_STORAGEBUFFER) { - _sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_STORAGEBUFFER, buf->slot.id); - } - if (buf->wgpu.buf) { - wgpuBufferRelease(buf->wgpu.buf); - } -} - -_SOKOL_PRIVATE void _sg_wgpu_copy_buffer_data(const _sg_buffer_t* buf, uint64_t offset, const sg_range* data) { - SOKOL_ASSERT((offset + data->size) <= (size_t)buf->cmn.size); - // WebGPU's write-buffer requires the size to be a multiple of four, so we may need to split the copy - // operation into two writeBuffer calls - uint64_t clamped_size = data->size & ~3UL; - uint64_t extra_size = data->size & 3UL; - SOKOL_ASSERT(extra_size < 4); - wgpuQueueWriteBuffer(_sg.wgpu.queue, buf->wgpu.buf, offset, data->ptr, clamped_size); - if (extra_size > 0) { - const uint64_t extra_src_offset = clamped_size; - const uint64_t extra_dst_offset = offset + clamped_size; - uint8_t extra_data[4] = { 0 }; - uint8_t* extra_src_ptr = ((uint8_t*)data->ptr) + extra_src_offset; - for (size_t i = 0; i < extra_size; i++) { - extra_data[i] = extra_src_ptr[i]; - } - wgpuQueueWriteBuffer(_sg.wgpu.queue, buf->wgpu.buf, extra_dst_offset, extra_src_ptr, 4); - } -} - -_SOKOL_PRIVATE void _sg_wgpu_copy_image_data(const _sg_image_t* img, WGPUTexture wgpu_tex, const sg_image_data* data) { - WGPUTextureDataLayout wgpu_layout; - _sg_clear(&wgpu_layout, sizeof(wgpu_layout)); - WGPUImageCopyTexture wgpu_copy_tex; - _sg_clear(&wgpu_copy_tex, sizeof(wgpu_copy_tex)); - wgpu_copy_tex.texture = wgpu_tex; - wgpu_copy_tex.aspect = WGPUTextureAspect_All; - WGPUExtent3D wgpu_extent; - _sg_clear(&wgpu_extent, sizeof(wgpu_extent)); - const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6 : 1; - for (int face_index = 0; face_index < num_faces; face_index++) { - for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++) { - wgpu_copy_tex.mipLevel = (uint32_t)mip_index; - wgpu_copy_tex.origin.z = (uint32_t)face_index; - int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); - int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); - int mip_slices; - switch (img->cmn.type) { - case SG_IMAGETYPE_CUBE: - mip_slices = 1; - break; - case SG_IMAGETYPE_3D: - mip_slices = _sg_miplevel_dim(img->cmn.num_slices, mip_index); - break; - default: - mip_slices = img->cmn.num_slices; - break; - } - const int row_pitch = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); - const int num_rows = _sg_num_rows(img->cmn.pixel_format, mip_height); - if (_sg_is_compressed_pixel_format(img->cmn.pixel_format)) { - mip_width = _sg_roundup(mip_width, 4); - mip_height = _sg_roundup(mip_height, 4); - } - wgpu_layout.offset = 0; - wgpu_layout.bytesPerRow = (uint32_t)row_pitch; - wgpu_layout.rowsPerImage = (uint32_t)num_rows; - wgpu_extent.width = (uint32_t)mip_width; - wgpu_extent.height = (uint32_t)mip_height; - wgpu_extent.depthOrArrayLayers = (uint32_t)mip_slices; - const sg_range* mip_data = &data->subimage[face_index][mip_index]; - wgpuQueueWriteTexture(_sg.wgpu.queue, &wgpu_copy_tex, mip_data->ptr, mip_data->size, &wgpu_layout, &wgpu_extent); - } - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_image(_sg_image_t* img, const sg_image_desc* desc) { - SOKOL_ASSERT(img && desc); - const bool injected = (0 != desc->wgpu_texture); - if (injected) { - img->wgpu.tex = (WGPUTexture)desc->wgpu_texture; - wgpuTextureReference(img->wgpu.tex); - img->wgpu.view = (WGPUTextureView)desc->wgpu_texture_view; - if (img->wgpu.view) { - wgpuTextureViewReference(img->wgpu.view); - } - } else { - WGPUTextureDescriptor wgpu_tex_desc; - _sg_clear(&wgpu_tex_desc, sizeof(wgpu_tex_desc)); - wgpu_tex_desc.label = desc->label; - wgpu_tex_desc.usage = WGPUTextureUsage_TextureBinding|WGPUTextureUsage_CopyDst; - if (desc->render_target) { - wgpu_tex_desc.usage |= WGPUTextureUsage_RenderAttachment; - } - wgpu_tex_desc.dimension = _sg_wgpu_texture_dimension(img->cmn.type); - wgpu_tex_desc.size.width = (uint32_t) img->cmn.width; - wgpu_tex_desc.size.height = (uint32_t) img->cmn.height; - if (desc->type == SG_IMAGETYPE_CUBE) { - wgpu_tex_desc.size.depthOrArrayLayers = 6; - } else { - wgpu_tex_desc.size.depthOrArrayLayers = (uint32_t) img->cmn.num_slices; - } - wgpu_tex_desc.format = _sg_wgpu_textureformat(img->cmn.pixel_format); - wgpu_tex_desc.mipLevelCount = (uint32_t) img->cmn.num_mipmaps; - wgpu_tex_desc.sampleCount = (uint32_t) img->cmn.sample_count; - img->wgpu.tex = wgpuDeviceCreateTexture(_sg.wgpu.dev, &wgpu_tex_desc); - if (0 == img->wgpu.tex) { - _SG_ERROR(WGPU_CREATE_TEXTURE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - if ((img->cmn.usage == SG_USAGE_IMMUTABLE) && !img->cmn.render_target) { - _sg_wgpu_copy_image_data(img, img->wgpu.tex, &desc->data); - } - WGPUTextureViewDescriptor wgpu_texview_desc; - _sg_clear(&wgpu_texview_desc, sizeof(wgpu_texview_desc)); - wgpu_texview_desc.label = desc->label; - wgpu_texview_desc.dimension = _sg_wgpu_texture_view_dimension(img->cmn.type); - wgpu_texview_desc.mipLevelCount = (uint32_t)img->cmn.num_mipmaps; - if (img->cmn.type == SG_IMAGETYPE_CUBE) { - wgpu_texview_desc.arrayLayerCount = 6; - } else if (img->cmn.type == SG_IMAGETYPE_ARRAY) { - wgpu_texview_desc.arrayLayerCount = (uint32_t)img->cmn.num_slices; - } else { - wgpu_texview_desc.arrayLayerCount = 1; - } - if (_sg_is_depth_or_depth_stencil_format(img->cmn.pixel_format)) { - wgpu_texview_desc.aspect = WGPUTextureAspect_DepthOnly; - } else { - wgpu_texview_desc.aspect = WGPUTextureAspect_All; - } - img->wgpu.view = wgpuTextureCreateView(img->wgpu.tex, &wgpu_texview_desc); - if (0 == img->wgpu.view) { - _SG_ERROR(WGPU_CREATE_TEXTURE_VIEW_FAILED); - return SG_RESOURCESTATE_FAILED; - } - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_image(_sg_image_t* img) { - SOKOL_ASSERT(img); - _sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_IMAGE, img->slot.id); - if (img->wgpu.view) { - wgpuTextureViewRelease(img->wgpu.view); - img->wgpu.view = 0; - } - if (img->wgpu.tex) { - wgpuTextureRelease(img->wgpu.tex); - img->wgpu.tex = 0; - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_sampler(_sg_sampler_t* smp, const sg_sampler_desc* desc) { - SOKOL_ASSERT(smp && desc); - SOKOL_ASSERT(_sg.wgpu.dev); - const bool injected = (0 != desc->wgpu_sampler); - if (injected) { - smp->wgpu.smp = (WGPUSampler) desc->wgpu_sampler; - wgpuSamplerReference(smp->wgpu.smp); - } else { - WGPUSamplerDescriptor wgpu_desc; - _sg_clear(&wgpu_desc, sizeof(wgpu_desc)); - wgpu_desc.label = desc->label; - wgpu_desc.addressModeU = _sg_wgpu_sampler_address_mode(desc->wrap_u); - wgpu_desc.addressModeV = _sg_wgpu_sampler_address_mode(desc->wrap_v); - wgpu_desc.addressModeW = _sg_wgpu_sampler_address_mode(desc->wrap_w); - wgpu_desc.magFilter = _sg_wgpu_sampler_minmag_filter(desc->mag_filter); - wgpu_desc.minFilter = _sg_wgpu_sampler_minmag_filter(desc->min_filter); - wgpu_desc.mipmapFilter = _sg_wgpu_sampler_mipmap_filter(desc->mipmap_filter); - wgpu_desc.lodMinClamp = desc->min_lod; - wgpu_desc.lodMaxClamp = desc->max_lod; - wgpu_desc.compare = _sg_wgpu_comparefunc(desc->compare); - if (wgpu_desc.compare == WGPUCompareFunction_Never) { - wgpu_desc.compare = WGPUCompareFunction_Undefined; - } - wgpu_desc.maxAnisotropy = (uint16_t)desc->max_anisotropy; - smp->wgpu.smp = wgpuDeviceCreateSampler(_sg.wgpu.dev, &wgpu_desc); - if (0 == smp->wgpu.smp) { - _SG_ERROR(WGPU_CREATE_SAMPLER_FAILED); - return SG_RESOURCESTATE_FAILED; - } - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_sampler(_sg_sampler_t* smp) { - SOKOL_ASSERT(smp); - _sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_SAMPLER, smp->slot.id); - if (smp->wgpu.smp) { - wgpuSamplerRelease(smp->wgpu.smp); - smp->wgpu.smp = 0; - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { - SOKOL_ASSERT(shd && desc); - SOKOL_ASSERT(desc->vs.source && desc->fs.source); - - WGPUBindGroupLayoutEntry wgpu_bgl_entries[_SG_WGPU_MAX_BINDGROUP_ENTRIES]; - _sg_clear(wgpu_bgl_entries, sizeof(wgpu_bgl_entries)); - int bgl_index = 0; - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS) ? &desc->vs : &desc->fs; - - _sg_shader_stage_t* cmn_stage = &shd->cmn.stage[stage_index]; - _sg_wgpu_shader_stage_t* wgpu_stage = &shd->wgpu.stage[stage_index]; - _sg_strcpy(&wgpu_stage->entry, stage_desc->entry); - - WGPUShaderModuleWGSLDescriptor wgpu_shdmod_wgsl_desc; - _sg_clear(&wgpu_shdmod_wgsl_desc, sizeof(wgpu_shdmod_wgsl_desc)); - wgpu_shdmod_wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor; - wgpu_shdmod_wgsl_desc.code = stage_desc->source; - - WGPUShaderModuleDescriptor wgpu_shdmod_desc; - _sg_clear(&wgpu_shdmod_desc, sizeof(wgpu_shdmod_desc)); - wgpu_shdmod_desc.nextInChain = &wgpu_shdmod_wgsl_desc.chain; - wgpu_shdmod_desc.label = desc->label; - - wgpu_stage->module = wgpuDeviceCreateShaderModule(_sg.wgpu.dev, &wgpu_shdmod_desc); - if (0 == wgpu_stage->module) { - _SG_ERROR(WGPU_CREATE_SHADER_MODULE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - - const int num_images = cmn_stage->num_images; - if (num_images > (int)_sg.wgpu.limits.limits.maxSampledTexturesPerShaderStage) { - _SG_ERROR(WGPU_SHADER_TOO_MANY_IMAGES); - return SG_RESOURCESTATE_FAILED; - } - const int num_samplers = cmn_stage->num_samplers; - if (num_samplers > (int)_sg.wgpu.limits.limits.maxSamplersPerShaderStage) { - _SG_ERROR(WGPU_SHADER_TOO_MANY_SAMPLERS); - return SG_RESOURCESTATE_FAILED; - } - const int num_sbufs = cmn_stage->num_storage_buffers; - if (num_sbufs > (int)_sg.wgpu.limits.limits.maxStorageBuffersPerShaderStage) { - _SG_ERROR(WGPU_SHADER_TOO_MANY_STORAGEBUFFERS); - return SG_RESOURCESTATE_FAILED; - } - for (int img_index = 0; img_index < num_images; img_index++) { - SOKOL_ASSERT(bgl_index < _SG_WGPU_MAX_BINDGROUP_ENTRIES); - WGPUBindGroupLayoutEntry* wgpu_bgl_entry = &wgpu_bgl_entries[bgl_index++]; - const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; - wgpu_bgl_entry->binding = _sg_wgpu_image_binding((sg_shader_stage)stage_index, img_index); - wgpu_bgl_entry->visibility = _sg_wgpu_shader_stage((sg_shader_stage)stage_index); - wgpu_bgl_entry->texture.viewDimension = _sg_wgpu_texture_view_dimension(img_desc->image_type); - wgpu_bgl_entry->texture.sampleType = _sg_wgpu_texture_sample_type(img_desc->sample_type); - wgpu_bgl_entry->texture.multisampled = img_desc->multisampled; - } - for (int smp_index = 0; smp_index < num_samplers; smp_index++) { - SOKOL_ASSERT(bgl_index < _SG_WGPU_MAX_BINDGROUP_ENTRIES); - WGPUBindGroupLayoutEntry* wgpu_bgl_entry = &wgpu_bgl_entries[bgl_index++]; - const sg_shader_sampler_desc* smp_desc = &stage_desc->samplers[smp_index]; - wgpu_bgl_entry->binding = _sg_wgpu_sampler_binding((sg_shader_stage)stage_index, smp_index); - wgpu_bgl_entry->visibility = _sg_wgpu_shader_stage((sg_shader_stage)stage_index); - wgpu_bgl_entry->sampler.type = _sg_wgpu_sampler_binding_type(smp_desc->sampler_type); - } - for (int sbuf_index = 0; sbuf_index < num_sbufs; sbuf_index++) { - SOKOL_ASSERT(bgl_index < _SG_WGPU_MAX_BINDGROUP_ENTRIES); - WGPUBindGroupLayoutEntry* wgpu_bgl_entry = &wgpu_bgl_entries[bgl_index++]; - const sg_shader_storage_buffer_desc* sbuf_desc = &stage_desc->storage_buffers[sbuf_index]; - wgpu_bgl_entry->binding = _sg_wgpu_storagebuffer_binding((sg_shader_stage)stage_index, sbuf_index); - wgpu_bgl_entry->visibility = _sg_wgpu_shader_stage((sg_shader_stage)stage_index); - wgpu_bgl_entry->buffer.type = sbuf_desc->readonly ? WGPUBufferBindingType_ReadOnlyStorage : WGPUBufferBindingType_Storage; - } - } - - WGPUBindGroupLayoutDescriptor wgpu_bgl_desc; - _sg_clear(&wgpu_bgl_desc, sizeof(wgpu_bgl_desc)); - wgpu_bgl_desc.entryCount = (size_t)bgl_index; - wgpu_bgl_desc.entries = &wgpu_bgl_entries[0]; - shd->wgpu.bind_group_layout = wgpuDeviceCreateBindGroupLayout(_sg.wgpu.dev, &wgpu_bgl_desc); - if (shd->wgpu.bind_group_layout == 0) { - _SG_ERROR(WGPU_SHADER_CREATE_BINDGROUP_LAYOUT_FAILED); - return SG_RESOURCESTATE_FAILED; - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_shader(_sg_shader_t* shd) { - SOKOL_ASSERT(shd); - if (shd->wgpu.bind_group_layout) { - wgpuBindGroupLayoutRelease(shd->wgpu.bind_group_layout); - shd->wgpu.bind_group_layout = 0; - } - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - _sg_wgpu_shader_stage_t* wgpu_stage = &shd->wgpu.stage[stage_index]; - if (wgpu_stage->module) { - wgpuShaderModuleRelease(wgpu_stage->module); - wgpu_stage->module = 0; - } - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { - SOKOL_ASSERT(pip && shd && desc); - SOKOL_ASSERT(desc->shader.id == shd->slot.id); - SOKOL_ASSERT(shd->wgpu.bind_group_layout); - pip->shader = shd; - - pip->wgpu.blend_color.r = (double) desc->blend_color.r; - pip->wgpu.blend_color.g = (double) desc->blend_color.g; - pip->wgpu.blend_color.b = (double) desc->blend_color.b; - pip->wgpu.blend_color.a = (double) desc->blend_color.a; - - // - @group(0) for uniform blocks - // - @group(1) for all image and sampler resources - WGPUBindGroupLayout wgpu_bgl[_SG_WGPU_NUM_BINDGROUPS]; - _sg_clear(&wgpu_bgl, sizeof(wgpu_bgl)); - wgpu_bgl[_SG_WGPU_UNIFORM_BINDGROUP_INDEX] = _sg.wgpu.uniform.bind.group_layout; - wgpu_bgl[_SG_WGPU_IMAGE_SAMPLER_BINDGROUP_INDEX] = shd->wgpu.bind_group_layout; - WGPUPipelineLayoutDescriptor wgpu_pl_desc; - _sg_clear(&wgpu_pl_desc, sizeof(wgpu_pl_desc)); - wgpu_pl_desc.bindGroupLayoutCount = _SG_WGPU_NUM_BINDGROUPS; - wgpu_pl_desc.bindGroupLayouts = &wgpu_bgl[0]; - const WGPUPipelineLayout wgpu_pip_layout = wgpuDeviceCreatePipelineLayout(_sg.wgpu.dev, &wgpu_pl_desc); - if (0 == wgpu_pip_layout) { - _SG_ERROR(WGPU_CREATE_PIPELINE_LAYOUT_FAILED); - return SG_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT(wgpu_pip_layout); - - WGPUVertexBufferLayout wgpu_vb_layouts[SG_MAX_VERTEX_BUFFERS]; - _sg_clear(wgpu_vb_layouts, sizeof(wgpu_vb_layouts)); - WGPUVertexAttribute wgpu_vtx_attrs[SG_MAX_VERTEX_BUFFERS][SG_MAX_VERTEX_ATTRIBUTES]; - _sg_clear(wgpu_vtx_attrs, sizeof(wgpu_vtx_attrs)); - int wgpu_vb_num = 0; - for (int vb_idx = 0; vb_idx < SG_MAX_VERTEX_BUFFERS; vb_idx++, wgpu_vb_num++) { - const sg_vertex_buffer_layout_state* vbl_state = &desc->layout.buffers[vb_idx]; - if (0 == vbl_state->stride) { - break; - } - wgpu_vb_layouts[vb_idx].arrayStride = (uint64_t)vbl_state->stride; - wgpu_vb_layouts[vb_idx].stepMode = _sg_wgpu_stepmode(vbl_state->step_func); - wgpu_vb_layouts[vb_idx].attributes = &wgpu_vtx_attrs[vb_idx][0]; - } - for (int va_idx = 0; va_idx < SG_MAX_VERTEX_ATTRIBUTES; va_idx++) { - const sg_vertex_attr_state* va_state = &desc->layout.attrs[va_idx]; - if (SG_VERTEXFORMAT_INVALID == va_state->format) { - break; - } - const int vb_idx = va_state->buffer_index; - SOKOL_ASSERT(vb_idx < SG_MAX_VERTEX_BUFFERS); - pip->cmn.vertex_buffer_layout_active[vb_idx] = true; - const size_t wgpu_attr_idx = wgpu_vb_layouts[vb_idx].attributeCount; - wgpu_vb_layouts[vb_idx].attributeCount += 1; - wgpu_vtx_attrs[vb_idx][wgpu_attr_idx].format = _sg_wgpu_vertexformat(va_state->format); - wgpu_vtx_attrs[vb_idx][wgpu_attr_idx].offset = (uint64_t)va_state->offset; - wgpu_vtx_attrs[vb_idx][wgpu_attr_idx].shaderLocation = (uint32_t)va_idx; - } - - WGPURenderPipelineDescriptor wgpu_pip_desc; - _sg_clear(&wgpu_pip_desc, sizeof(wgpu_pip_desc)); - WGPUDepthStencilState wgpu_ds_state; - _sg_clear(&wgpu_ds_state, sizeof(wgpu_ds_state)); - WGPUFragmentState wgpu_frag_state; - _sg_clear(&wgpu_frag_state, sizeof(wgpu_frag_state)); - WGPUColorTargetState wgpu_ctgt_state[SG_MAX_COLOR_ATTACHMENTS]; - _sg_clear(&wgpu_ctgt_state, sizeof(wgpu_ctgt_state)); - WGPUBlendState wgpu_blend_state[SG_MAX_COLOR_ATTACHMENTS]; - _sg_clear(&wgpu_blend_state, sizeof(wgpu_blend_state)); - wgpu_pip_desc.label = desc->label; - wgpu_pip_desc.layout = wgpu_pip_layout; - wgpu_pip_desc.vertex.module = shd->wgpu.stage[SG_SHADERSTAGE_VS].module; - wgpu_pip_desc.vertex.entryPoint = shd->wgpu.stage[SG_SHADERSTAGE_VS].entry.buf; - wgpu_pip_desc.vertex.bufferCount = (size_t)wgpu_vb_num; - wgpu_pip_desc.vertex.buffers = &wgpu_vb_layouts[0]; - wgpu_pip_desc.primitive.topology = _sg_wgpu_topology(desc->primitive_type); - wgpu_pip_desc.primitive.stripIndexFormat = _sg_wgpu_stripindexformat(desc->primitive_type, desc->index_type); - wgpu_pip_desc.primitive.frontFace = _sg_wgpu_frontface(desc->face_winding); - wgpu_pip_desc.primitive.cullMode = _sg_wgpu_cullmode(desc->cull_mode); - if (SG_PIXELFORMAT_NONE != desc->depth.pixel_format) { - wgpu_ds_state.format = _sg_wgpu_textureformat(desc->depth.pixel_format); - wgpu_ds_state.depthWriteEnabled = desc->depth.write_enabled; - wgpu_ds_state.depthCompare = _sg_wgpu_comparefunc(desc->depth.compare); - wgpu_ds_state.stencilFront.compare = _sg_wgpu_comparefunc(desc->stencil.front.compare); - wgpu_ds_state.stencilFront.failOp = _sg_wgpu_stencilop(desc->stencil.front.fail_op); - wgpu_ds_state.stencilFront.depthFailOp = _sg_wgpu_stencilop(desc->stencil.front.depth_fail_op); - wgpu_ds_state.stencilFront.passOp = _sg_wgpu_stencilop(desc->stencil.front.pass_op); - wgpu_ds_state.stencilBack.compare = _sg_wgpu_comparefunc(desc->stencil.back.compare); - wgpu_ds_state.stencilBack.failOp = _sg_wgpu_stencilop(desc->stencil.back.fail_op); - wgpu_ds_state.stencilBack.depthFailOp = _sg_wgpu_stencilop(desc->stencil.back.depth_fail_op); - wgpu_ds_state.stencilBack.passOp = _sg_wgpu_stencilop(desc->stencil.back.pass_op); - wgpu_ds_state.stencilReadMask = desc->stencil.read_mask; - wgpu_ds_state.stencilWriteMask = desc->stencil.write_mask; - wgpu_ds_state.depthBias = (int32_t)desc->depth.bias; - wgpu_ds_state.depthBiasSlopeScale = desc->depth.bias_slope_scale; - wgpu_ds_state.depthBiasClamp = desc->depth.bias_clamp; - wgpu_pip_desc.depthStencil = &wgpu_ds_state; - } - wgpu_pip_desc.multisample.count = (uint32_t)desc->sample_count; - wgpu_pip_desc.multisample.mask = 0xFFFFFFFF; - wgpu_pip_desc.multisample.alphaToCoverageEnabled = desc->alpha_to_coverage_enabled; - if (desc->color_count > 0) { - wgpu_frag_state.module = shd->wgpu.stage[SG_SHADERSTAGE_FS].module; - wgpu_frag_state.entryPoint = shd->wgpu.stage[SG_SHADERSTAGE_FS].entry.buf; - wgpu_frag_state.targetCount = (size_t)desc->color_count; - wgpu_frag_state.targets = &wgpu_ctgt_state[0]; - for (int i = 0; i < desc->color_count; i++) { - SOKOL_ASSERT(i < SG_MAX_COLOR_ATTACHMENTS); - wgpu_ctgt_state[i].format = _sg_wgpu_textureformat(desc->colors[i].pixel_format); - wgpu_ctgt_state[i].writeMask = _sg_wgpu_colorwritemask(desc->colors[i].write_mask); - if (desc->colors[i].blend.enabled) { - wgpu_ctgt_state[i].blend = &wgpu_blend_state[i]; - wgpu_blend_state[i].color.operation = _sg_wgpu_blendop(desc->colors[i].blend.op_rgb); - wgpu_blend_state[i].color.srcFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.src_factor_rgb); - wgpu_blend_state[i].color.dstFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.dst_factor_rgb); - wgpu_blend_state[i].alpha.operation = _sg_wgpu_blendop(desc->colors[i].blend.op_alpha); - wgpu_blend_state[i].alpha.srcFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.src_factor_alpha); - wgpu_blend_state[i].alpha.dstFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.dst_factor_alpha); - } - } - wgpu_pip_desc.fragment = &wgpu_frag_state; - } - pip->wgpu.pip = wgpuDeviceCreateRenderPipeline(_sg.wgpu.dev, &wgpu_pip_desc); - wgpuPipelineLayoutRelease(wgpu_pip_layout); - if (0 == pip->wgpu.pip) { - _SG_ERROR(WGPU_CREATE_RENDER_PIPELINE_FAILED); - return SG_RESOURCESTATE_FAILED; - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - _sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_PIPELINE, pip->slot.id); - if (pip == _sg.wgpu.cur_pipeline) { - _sg.wgpu.cur_pipeline = 0; - _sg.wgpu.cur_pipeline_id.id = SG_INVALID_ID; - } - if (pip->wgpu.pip) { - wgpuRenderPipelineRelease(pip->wgpu.pip); - pip->wgpu.pip = 0; - } -} - -_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_attachments_desc* desc) { - SOKOL_ASSERT(atts && desc); - SOKOL_ASSERT(color_images && resolve_images); - - // copy image pointers and create renderable wgpu texture views - for (int i = 0; i < atts->cmn.num_colors; i++) { - const sg_attachment_desc* color_desc = &desc->colors[i]; - _SOKOL_UNUSED(color_desc); - SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == atts->wgpu.colors[i].image); - SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); - SOKOL_ASSERT(color_images[i]->wgpu.tex); - atts->wgpu.colors[i].image = color_images[i]; - - WGPUTextureViewDescriptor wgpu_color_view_desc; - _sg_clear(&wgpu_color_view_desc, sizeof(wgpu_color_view_desc)); - wgpu_color_view_desc.baseMipLevel = (uint32_t) color_desc->mip_level; - wgpu_color_view_desc.mipLevelCount = 1; - wgpu_color_view_desc.baseArrayLayer = (uint32_t) color_desc->slice; - wgpu_color_view_desc.arrayLayerCount = 1; - atts->wgpu.colors[i].view = wgpuTextureCreateView(color_images[i]->wgpu.tex, &wgpu_color_view_desc); - if (0 == atts->wgpu.colors[i].view) { - _SG_ERROR(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED); - return SG_RESOURCESTATE_FAILED; - } - - const sg_attachment_desc* resolve_desc = &desc->resolves[i]; - if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == atts->wgpu.resolves[i].image); - SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); - SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); - SOKOL_ASSERT(resolve_images[i]->wgpu.tex); - atts->wgpu.resolves[i].image = resolve_images[i]; - - WGPUTextureViewDescriptor wgpu_resolve_view_desc; - _sg_clear(&wgpu_resolve_view_desc, sizeof(wgpu_resolve_view_desc)); - wgpu_resolve_view_desc.baseMipLevel = (uint32_t) resolve_desc->mip_level; - wgpu_resolve_view_desc.mipLevelCount = 1; - wgpu_resolve_view_desc.baseArrayLayer = (uint32_t) resolve_desc->slice; - wgpu_resolve_view_desc.arrayLayerCount = 1; - atts->wgpu.resolves[i].view = wgpuTextureCreateView(resolve_images[i]->wgpu.tex, &wgpu_resolve_view_desc); - if (0 == atts->wgpu.resolves[i].view) { - _SG_ERROR(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED); - return SG_RESOURCESTATE_FAILED; - } - } - } - SOKOL_ASSERT(0 == atts->wgpu.depth_stencil.image); - const sg_attachment_desc* ds_desc = &desc->depth_stencil; - if (ds_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(ds_img && (ds_img->slot.id == ds_desc->image.id)); - SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_img->cmn.pixel_format)); - SOKOL_ASSERT(ds_img->wgpu.tex); - atts->wgpu.depth_stencil.image = ds_img; - - WGPUTextureViewDescriptor wgpu_ds_view_desc; - _sg_clear(&wgpu_ds_view_desc, sizeof(wgpu_ds_view_desc)); - wgpu_ds_view_desc.baseMipLevel = (uint32_t) ds_desc->mip_level; - wgpu_ds_view_desc.mipLevelCount = 1; - wgpu_ds_view_desc.baseArrayLayer = (uint32_t) ds_desc->slice; - wgpu_ds_view_desc.arrayLayerCount = 1; - atts->wgpu.depth_stencil.view = wgpuTextureCreateView(ds_img->wgpu.tex, &wgpu_ds_view_desc); - if (0 == atts->wgpu.depth_stencil.view) { - _SG_ERROR(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED); - return SG_RESOURCESTATE_FAILED; - } - } - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_attachments(_sg_attachments_t* atts) { - SOKOL_ASSERT(atts); - for (int i = 0; i < atts->cmn.num_colors; i++) { - if (atts->wgpu.colors[i].view) { - wgpuTextureViewRelease(atts->wgpu.colors[i].view); - atts->wgpu.colors[i].view = 0; - } - if (atts->wgpu.resolves[i].view) { - wgpuTextureViewRelease(atts->wgpu.resolves[i].view); - atts->wgpu.resolves[i].view = 0; - } - } - if (atts->wgpu.depth_stencil.view) { - wgpuTextureViewRelease(atts->wgpu.depth_stencil.view); - atts->wgpu.depth_stencil.view = 0; - } -} - -_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_attachments_color_image(const _sg_attachments_t* atts, int index) { - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - // NOTE: may return null - return atts->wgpu.colors[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_attachments_resolve_image(const _sg_attachments_t* atts, int index) { - SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - // NOTE: may return null - return atts->wgpu.resolves[index].image; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_attachments_ds_image(const _sg_attachments_t* atts) { - // NOTE: may return null - SOKOL_ASSERT(atts); - return atts->wgpu.depth_stencil.image; -} - -_SOKOL_PRIVATE void _sg_wgpu_init_color_att(WGPURenderPassColorAttachment* wgpu_att, const sg_color_attachment_action* action, WGPUTextureView color_view, WGPUTextureView resolve_view) { - wgpu_att->depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; - wgpu_att->view = color_view; - wgpu_att->resolveTarget = resolve_view; - wgpu_att->loadOp = _sg_wgpu_load_op(color_view, action->load_action); - wgpu_att->storeOp = _sg_wgpu_store_op(color_view, action->store_action); - wgpu_att->clearValue.r = action->clear_value.r; - wgpu_att->clearValue.g = action->clear_value.g; - wgpu_att->clearValue.b = action->clear_value.b; - wgpu_att->clearValue.a = action->clear_value.a; -} - -_SOKOL_PRIVATE void _sg_wgpu_init_ds_att(WGPURenderPassDepthStencilAttachment* wgpu_att, const sg_pass_action* action, sg_pixel_format fmt, WGPUTextureView view) { - wgpu_att->view = view; - wgpu_att->depthLoadOp = _sg_wgpu_load_op(view, action->depth.load_action); - wgpu_att->depthStoreOp = _sg_wgpu_store_op(view, action->depth.store_action); - wgpu_att->depthClearValue = action->depth.clear_value; - wgpu_att->depthReadOnly = false; - if (_sg_is_depth_stencil_format(fmt)) { - wgpu_att->stencilLoadOp = _sg_wgpu_load_op(view, action->stencil.load_action); - wgpu_att->stencilStoreOp = _sg_wgpu_store_op(view, action->stencil.store_action); - } else { - wgpu_att->stencilLoadOp = WGPULoadOp_Undefined; - wgpu_att->stencilStoreOp = WGPUStoreOp_Undefined; - } - wgpu_att->stencilClearValue = action->stencil.clear_value; - wgpu_att->stencilReadOnly = false; -} - -_SOKOL_PRIVATE void _sg_wgpu_begin_pass(const sg_pass* pass) { - SOKOL_ASSERT(pass); - SOKOL_ASSERT(_sg.wgpu.cmd_enc); - SOKOL_ASSERT(_sg.wgpu.dev); - - const _sg_attachments_t* atts = _sg.cur_pass.atts; - const sg_swapchain* swapchain = &pass->swapchain; - const sg_pass_action* action = &pass->action; - - _sg.wgpu.cur_pipeline = 0; - _sg.wgpu.cur_pipeline_id.id = SG_INVALID_ID; - - WGPURenderPassDescriptor wgpu_pass_desc; - WGPURenderPassColorAttachment wgpu_color_att[SG_MAX_COLOR_ATTACHMENTS]; - WGPURenderPassDepthStencilAttachment wgpu_ds_att; - _sg_clear(&wgpu_pass_desc, sizeof(wgpu_pass_desc)); - _sg_clear(&wgpu_color_att, sizeof(wgpu_color_att)); - _sg_clear(&wgpu_ds_att, sizeof(wgpu_ds_att)); - wgpu_pass_desc.label = pass->label; - if (atts) { - SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_VALID); - for (int i = 0; i < atts->cmn.num_colors; i++) { - _sg_wgpu_init_color_att(&wgpu_color_att[i], &action->colors[i], atts->wgpu.colors[i].view, atts->wgpu.resolves[i].view); - } - wgpu_pass_desc.colorAttachmentCount = (size_t)atts->cmn.num_colors; - wgpu_pass_desc.colorAttachments = &wgpu_color_att[0]; - if (atts->wgpu.depth_stencil.image) { - _sg_wgpu_init_ds_att(&wgpu_ds_att, action, atts->wgpu.depth_stencil.image->cmn.pixel_format, atts->wgpu.depth_stencil.view); - wgpu_pass_desc.depthStencilAttachment = &wgpu_ds_att; - } - } else { - WGPUTextureView wgpu_color_view = (WGPUTextureView) swapchain->wgpu.render_view; - WGPUTextureView wgpu_resolve_view = (WGPUTextureView) swapchain->wgpu.resolve_view; - WGPUTextureView wgpu_depth_stencil_view = (WGPUTextureView) swapchain->wgpu.depth_stencil_view; - _sg_wgpu_init_color_att(&wgpu_color_att[0], &action->colors[0], wgpu_color_view, wgpu_resolve_view); - wgpu_pass_desc.colorAttachmentCount = 1; - wgpu_pass_desc.colorAttachments = &wgpu_color_att[0]; - if (wgpu_depth_stencil_view) { - SOKOL_ASSERT(swapchain->depth_format > SG_PIXELFORMAT_NONE); - _sg_wgpu_init_ds_att(&wgpu_ds_att, action, swapchain->depth_format, wgpu_depth_stencil_view); - wgpu_pass_desc.depthStencilAttachment = &wgpu_ds_att; - } - } - _sg.wgpu.pass_enc = wgpuCommandEncoderBeginRenderPass(_sg.wgpu.cmd_enc, &wgpu_pass_desc); - SOKOL_ASSERT(_sg.wgpu.pass_enc); - - // clear bindings cache and apply an empty image-sampler bindgroup - _sg_wgpu_bindings_cache_clear(); - wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, _SG_WGPU_IMAGE_SAMPLER_BINDGROUP_INDEX, _sg.wgpu.empty_bind_group, 0, 0); - _sg_stats_add(wgpu.bindings.num_set_bindgroup, 1); - - // initial uniform buffer binding (required even if no uniforms are set in the frame) - _sg_wgpu_uniform_buffer_on_begin_pass(); -} - -_SOKOL_PRIVATE void _sg_wgpu_end_pass(void) { - if (_sg.wgpu.pass_enc) { - wgpuRenderPassEncoderEnd(_sg.wgpu.pass_enc); - wgpuRenderPassEncoderRelease(_sg.wgpu.pass_enc); - _sg.wgpu.pass_enc = 0; - } -} - -_SOKOL_PRIVATE void _sg_wgpu_commit(void) { - SOKOL_ASSERT(_sg.wgpu.cmd_enc); - - _sg_wgpu_uniform_buffer_on_commit(); - - WGPUCommandBufferDescriptor cmd_buf_desc; - _sg_clear(&cmd_buf_desc, sizeof(cmd_buf_desc)); - WGPUCommandBuffer wgpu_cmd_buf = wgpuCommandEncoderFinish(_sg.wgpu.cmd_enc, &cmd_buf_desc); - SOKOL_ASSERT(wgpu_cmd_buf); - wgpuCommandEncoderRelease(_sg.wgpu.cmd_enc); - _sg.wgpu.cmd_enc = 0; - - wgpuQueueSubmit(_sg.wgpu.queue, 1, &wgpu_cmd_buf); - wgpuCommandBufferRelease(wgpu_cmd_buf); - - // create a new render-command-encoder for next frame - WGPUCommandEncoderDescriptor cmd_enc_desc; - _sg_clear(&cmd_enc_desc, sizeof(cmd_enc_desc)); - _sg.wgpu.cmd_enc = wgpuDeviceCreateCommandEncoder(_sg.wgpu.dev, &cmd_enc_desc); -} - -_SOKOL_PRIVATE void _sg_wgpu_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.wgpu.pass_enc); - // FIXME FIXME FIXME: CLIPPING THE VIEWPORT HERE IS WRONG!!! - // (but currently required because WebGPU insists that the viewport rectangle must be - // fully contained inside the framebuffer, but this doesn't make any sense, and also - // isn't required by the backend APIs) - const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.width, _sg.cur_pass.height); - float xf = (float) clip.x; - float yf = (float) (origin_top_left ? clip.y : (_sg.cur_pass.height - (clip.y + clip.h))); - float wf = (float) clip.w; - float hf = (float) clip.h; - wgpuRenderPassEncoderSetViewport(_sg.wgpu.pass_enc, xf, yf, wf, hf, 0.0f, 1.0f); -} - -_SOKOL_PRIVATE void _sg_wgpu_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.wgpu.pass_enc); - const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.width, _sg.cur_pass.height); - uint32_t sx = (uint32_t) clip.x; - uint32_t sy = (uint32_t) (origin_top_left ? clip.y : (_sg.cur_pass.height - (clip.y + clip.h))); - uint32_t sw = (uint32_t) clip.w; - uint32_t sh = (uint32_t) clip.h; - wgpuRenderPassEncoderSetScissorRect(_sg.wgpu.pass_enc, sx, sy, sw, sh); -} - -_SOKOL_PRIVATE void _sg_wgpu_apply_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - SOKOL_ASSERT(pip->wgpu.pip); - SOKOL_ASSERT(_sg.wgpu.pass_enc); - _sg.wgpu.use_indexed_draw = (pip->cmn.index_type != SG_INDEXTYPE_NONE); - _sg.wgpu.cur_pipeline = pip; - _sg.wgpu.cur_pipeline_id.id = pip->slot.id; - wgpuRenderPassEncoderSetPipeline(_sg.wgpu.pass_enc, pip->wgpu.pip); - wgpuRenderPassEncoderSetBlendConstant(_sg.wgpu.pass_enc, &pip->wgpu.blend_color); - wgpuRenderPassEncoderSetStencilReference(_sg.wgpu.pass_enc, pip->cmn.stencil.ref); -} - -_SOKOL_PRIVATE bool _sg_wgpu_apply_bindings(_sg_bindings_t* bnd) { - SOKOL_ASSERT(_sg.wgpu.pass_enc); - SOKOL_ASSERT(bnd); - SOKOL_ASSERT(bnd->pip->shader && (bnd->pip->cmn.shader_id.id == bnd->pip->shader->slot.id)); - bool retval = true; - retval &= _sg_wgpu_apply_index_buffer(bnd); - retval &= _sg_wgpu_apply_vertex_buffers(bnd); - retval &= _sg_wgpu_apply_bindgroup(bnd); - return retval; -} - -_SOKOL_PRIVATE void _sg_wgpu_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { - const uint32_t alignment = _sg.wgpu.limits.limits.minUniformBufferOffsetAlignment; - SOKOL_ASSERT(_sg.wgpu.pass_enc); - SOKOL_ASSERT(_sg.wgpu.uniform.staging); - SOKOL_ASSERT((_sg.wgpu.uniform.offset + data->size) <= _sg.wgpu.uniform.num_bytes); - SOKOL_ASSERT((_sg.wgpu.uniform.offset & (alignment - 1)) == 0); - SOKOL_ASSERT(_sg.wgpu.cur_pipeline && _sg.wgpu.cur_pipeline->shader); - SOKOL_ASSERT(_sg.wgpu.cur_pipeline->slot.id == _sg.wgpu.cur_pipeline_id.id); - SOKOL_ASSERT(_sg.wgpu.cur_pipeline->shader->slot.id == _sg.wgpu.cur_pipeline->cmn.shader_id.id); - SOKOL_ASSERT(ub_index < _sg.wgpu.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); - SOKOL_ASSERT(data->size <= _sg.wgpu.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); - SOKOL_ASSERT(data->size <= _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE); - - _sg_stats_add(wgpu.uniforms.num_set_bindgroup, 1); - memcpy(_sg.wgpu.uniform.staging + _sg.wgpu.uniform.offset, data->ptr, data->size); - _sg.wgpu.uniform.bind.offsets[stage_index][ub_index] = _sg.wgpu.uniform.offset; - _sg.wgpu.uniform.offset = _sg_roundup_u32(_sg.wgpu.uniform.offset + (uint32_t)data->size, alignment); - wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, - _SG_WGPU_UNIFORM_BINDGROUP_INDEX, - _sg.wgpu.uniform.bind.group, - SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_UBS, - &_sg.wgpu.uniform.bind.offsets[0][0]); -} - -_SOKOL_PRIVATE void _sg_wgpu_draw(int base_element, int num_elements, int num_instances) { - SOKOL_ASSERT(_sg.wgpu.pass_enc); - SOKOL_ASSERT(_sg.wgpu.cur_pipeline && (_sg.wgpu.cur_pipeline->slot.id == _sg.wgpu.cur_pipeline_id.id)); - if (SG_INDEXTYPE_NONE != _sg.wgpu.cur_pipeline->cmn.index_type) { - wgpuRenderPassEncoderDrawIndexed(_sg.wgpu.pass_enc, (uint32_t)num_elements, (uint32_t)num_instances, (uint32_t)base_element, 0, 0); - } else { - wgpuRenderPassEncoderDraw(_sg.wgpu.pass_enc, (uint32_t)num_elements, (uint32_t)num_instances, (uint32_t)base_element, 0); - } -} - -_SOKOL_PRIVATE void _sg_wgpu_update_buffer(_sg_buffer_t* buf, const sg_range* data) { - SOKOL_ASSERT(data && data->ptr && (data->size > 0)); - SOKOL_ASSERT(buf); - _sg_wgpu_copy_buffer_data(buf, 0, data); -} - -_SOKOL_PRIVATE void _sg_wgpu_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { - SOKOL_ASSERT(data && data->ptr && (data->size > 0)); - _SOKOL_UNUSED(new_frame); - _sg_wgpu_copy_buffer_data(buf, (uint64_t)buf->cmn.append_pos, data); -} - -_SOKOL_PRIVATE void _sg_wgpu_update_image(_sg_image_t* img, const sg_image_data* data) { - SOKOL_ASSERT(img && data); - _sg_wgpu_copy_image_data(img, img->wgpu.tex, data); -} -#endif - -// ██████ ███████ ███ ██ ███████ ██████ ██ ██████ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ -// ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██ ███ █████ ██ ██ ██ █████ ██████ ██ ██ ██████ ███████ ██ █████ █████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ███████ ██ ████ ███████ ██ ██ ██ ██████ ██████ ██ ██ ██████ ██ ██ ███████ ██ ████ ██████ -// -// >>generic backend -static inline void _sg_setup_backend(const sg_desc* desc) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_setup_backend(desc); - #elif defined(SOKOL_METAL) - _sg_mtl_setup_backend(desc); - #elif defined(SOKOL_D3D11) - _sg_d3d11_setup_backend(desc); - #elif defined(SOKOL_WGPU) - _sg_wgpu_setup_backend(desc); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_setup_backend(desc); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_discard_backend(void) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_discard_backend(); - #elif defined(SOKOL_METAL) - _sg_mtl_discard_backend(); - #elif defined(SOKOL_D3D11) - _sg_d3d11_discard_backend(); - #elif defined(SOKOL_WGPU) - _sg_wgpu_discard_backend(); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_discard_backend(); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_reset_state_cache(void) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_reset_state_cache(); - #elif defined(SOKOL_METAL) - _sg_mtl_reset_state_cache(); - #elif defined(SOKOL_D3D11) - _sg_d3d11_reset_state_cache(); - #elif defined(SOKOL_WGPU) - _sg_wgpu_reset_state_cache(); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_reset_state_cache(); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline sg_resource_state _sg_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_create_buffer(buf, desc); - #elif defined(SOKOL_METAL) - return _sg_mtl_create_buffer(buf, desc); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_create_buffer(buf, desc); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_create_buffer(buf, desc); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_create_buffer(buf, desc); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_discard_buffer(_sg_buffer_t* buf) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_discard_buffer(buf); - #elif defined(SOKOL_METAL) - _sg_mtl_discard_buffer(buf); - #elif defined(SOKOL_D3D11) - _sg_d3d11_discard_buffer(buf); - #elif defined(SOKOL_WGPU) - _sg_wgpu_discard_buffer(buf); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_discard_buffer(buf); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline sg_resource_state _sg_create_image(_sg_image_t* img, const sg_image_desc* desc) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_create_image(img, desc); - #elif defined(SOKOL_METAL) - return _sg_mtl_create_image(img, desc); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_create_image(img, desc); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_create_image(img, desc); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_create_image(img, desc); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_discard_image(_sg_image_t* img) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_discard_image(img); - #elif defined(SOKOL_METAL) - _sg_mtl_discard_image(img); - #elif defined(SOKOL_D3D11) - _sg_d3d11_discard_image(img); - #elif defined(SOKOL_WGPU) - _sg_wgpu_discard_image(img); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_discard_image(img); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline sg_resource_state _sg_create_sampler(_sg_sampler_t* smp, const sg_sampler_desc* desc) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_create_sampler(smp, desc); - #elif defined(SOKOL_METAL) - return _sg_mtl_create_sampler(smp, desc); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_create_sampler(smp, desc); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_create_sampler(smp, desc); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_create_sampler(smp, desc); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_discard_sampler(_sg_sampler_t* smp) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_discard_sampler(smp); - #elif defined(SOKOL_METAL) - _sg_mtl_discard_sampler(smp); - #elif defined(SOKOL_D3D11) - _sg_d3d11_discard_sampler(smp); - #elif defined(SOKOL_WGPU) - _sg_wgpu_discard_sampler(smp); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_discard_sampler(smp); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline sg_resource_state _sg_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_create_shader(shd, desc); - #elif defined(SOKOL_METAL) - return _sg_mtl_create_shader(shd, desc); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_create_shader(shd, desc); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_create_shader(shd, desc); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_create_shader(shd, desc); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_discard_shader(_sg_shader_t* shd) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_discard_shader(shd); - #elif defined(SOKOL_METAL) - _sg_mtl_discard_shader(shd); - #elif defined(SOKOL_D3D11) - _sg_d3d11_discard_shader(shd); - #elif defined(SOKOL_WGPU) - _sg_wgpu_discard_shader(shd); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_discard_shader(shd); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline sg_resource_state _sg_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_create_pipeline(pip, shd, desc); - #elif defined(SOKOL_METAL) - return _sg_mtl_create_pipeline(pip, shd, desc); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_create_pipeline(pip, shd, desc); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_create_pipeline(pip, shd, desc); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_create_pipeline(pip, shd, desc); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_discard_pipeline(_sg_pipeline_t* pip) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_discard_pipeline(pip); - #elif defined(SOKOL_METAL) - _sg_mtl_discard_pipeline(pip); - #elif defined(SOKOL_D3D11) - _sg_d3d11_discard_pipeline(pip); - #elif defined(SOKOL_WGPU) - _sg_wgpu_discard_pipeline(pip); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_discard_pipeline(pip); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline sg_resource_state _sg_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_image, const sg_attachments_desc* desc) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_create_attachments(atts, color_images, resolve_images, ds_image, desc); - #elif defined(SOKOL_METAL) - return _sg_mtl_create_attachments(atts, color_images, resolve_images, ds_image, desc); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_create_attachments(atts, color_images, resolve_images, ds_image, desc); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_create_attachments(atts, color_images, resolve_images, ds_image, desc); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_create_attachments(atts, color_images, resolve_images, ds_image, desc); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_discard_attachments(_sg_attachments_t* atts) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_discard_attachments(atts); - #elif defined(SOKOL_METAL) - _sg_mtl_discard_attachments(atts); - #elif defined(SOKOL_D3D11) - _sg_d3d11_discard_attachments(atts); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_discard_attachments(atts); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_discard_attachments(atts); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline _sg_image_t* _sg_attachments_color_image(const _sg_attachments_t* atts, int index) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_attachments_color_image(atts, index); - #elif defined(SOKOL_METAL) - return _sg_mtl_attachments_color_image(atts, index); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_attachments_color_image(atts, index); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_attachments_color_image(atts, index); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_attachments_color_image(atts, index); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline _sg_image_t* _sg_attachments_resolve_image(const _sg_attachments_t* atts, int index) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_attachments_resolve_image(atts, index); - #elif defined(SOKOL_METAL) - return _sg_mtl_attachments_resolve_image(atts, index); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_attachments_resolve_image(atts, index); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_attachments_resolve_image(atts, index); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_attachments_resolve_image(atts, index); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline _sg_image_t* _sg_attachments_ds_image(const _sg_attachments_t* atts) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_attachments_ds_image(atts); - #elif defined(SOKOL_METAL) - return _sg_mtl_attachments_ds_image(atts); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_attachments_ds_image(atts); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_attachments_ds_image(atts); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_attachments_ds_image(atts); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_begin_pass(const sg_pass* pass) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_begin_pass(pass); - #elif defined(SOKOL_METAL) - _sg_mtl_begin_pass(pass); - #elif defined(SOKOL_D3D11) - _sg_d3d11_begin_pass(pass); - #elif defined(SOKOL_WGPU) - _sg_wgpu_begin_pass(pass); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_begin_pass(pass); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_end_pass(void) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_end_pass(); - #elif defined(SOKOL_METAL) - _sg_mtl_end_pass(); - #elif defined(SOKOL_D3D11) - _sg_d3d11_end_pass(); - #elif defined(SOKOL_WGPU) - _sg_wgpu_end_pass(); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_end_pass(); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_apply_viewport(x, y, w, h, origin_top_left); - #elif defined(SOKOL_METAL) - _sg_mtl_apply_viewport(x, y, w, h, origin_top_left); - #elif defined(SOKOL_D3D11) - _sg_d3d11_apply_viewport(x, y, w, h, origin_top_left); - #elif defined(SOKOL_WGPU) - _sg_wgpu_apply_viewport(x, y, w, h, origin_top_left); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_apply_viewport(x, y, w, h, origin_top_left); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_apply_scissor_rect(x, y, w, h, origin_top_left); - #elif defined(SOKOL_METAL) - _sg_mtl_apply_scissor_rect(x, y, w, h, origin_top_left); - #elif defined(SOKOL_D3D11) - _sg_d3d11_apply_scissor_rect(x, y, w, h, origin_top_left); - #elif defined(SOKOL_WGPU) - _sg_wgpu_apply_scissor_rect(x, y, w, h, origin_top_left); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_apply_scissor_rect(x, y, w, h, origin_top_left); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_apply_pipeline(_sg_pipeline_t* pip) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_apply_pipeline(pip); - #elif defined(SOKOL_METAL) - _sg_mtl_apply_pipeline(pip); - #elif defined(SOKOL_D3D11) - _sg_d3d11_apply_pipeline(pip); - #elif defined(SOKOL_WGPU) - _sg_wgpu_apply_pipeline(pip); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_apply_pipeline(pip); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline bool _sg_apply_bindings(_sg_bindings_t* bnd) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_apply_bindings(bnd); - #elif defined(SOKOL_METAL) - return _sg_mtl_apply_bindings(bnd); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_apply_bindings(bnd); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_apply_bindings(bnd); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_apply_bindings(bnd); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_apply_uniforms(stage_index, ub_index, data); - #elif defined(SOKOL_METAL) - _sg_mtl_apply_uniforms(stage_index, ub_index, data); - #elif defined(SOKOL_D3D11) - _sg_d3d11_apply_uniforms(stage_index, ub_index, data); - #elif defined(SOKOL_WGPU) - _sg_wgpu_apply_uniforms(stage_index, ub_index, data); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_apply_uniforms(stage_index, ub_index, data); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_draw(int base_element, int num_elements, int num_instances) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_draw(base_element, num_elements, num_instances); - #elif defined(SOKOL_METAL) - _sg_mtl_draw(base_element, num_elements, num_instances); - #elif defined(SOKOL_D3D11) - _sg_d3d11_draw(base_element, num_elements, num_instances); - #elif defined(SOKOL_WGPU) - _sg_wgpu_draw(base_element, num_elements, num_instances); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_draw(base_element, num_elements, num_instances); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_commit(void) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_commit(); - #elif defined(SOKOL_METAL) - _sg_mtl_commit(); - #elif defined(SOKOL_D3D11) - _sg_d3d11_commit(); - #elif defined(SOKOL_WGPU) - _sg_wgpu_commit(); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_commit(); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_update_buffer(_sg_buffer_t* buf, const sg_range* data) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_update_buffer(buf, data); - #elif defined(SOKOL_METAL) - _sg_mtl_update_buffer(buf, data); - #elif defined(SOKOL_D3D11) - _sg_d3d11_update_buffer(buf, data); - #elif defined(SOKOL_WGPU) - _sg_wgpu_update_buffer(buf, data); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_update_buffer(buf, data); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_append_buffer(buf, data, new_frame); - #elif defined(SOKOL_METAL) - _sg_mtl_append_buffer(buf, data, new_frame); - #elif defined(SOKOL_D3D11) - _sg_d3d11_append_buffer(buf, data, new_frame); - #elif defined(SOKOL_WGPU) - _sg_wgpu_append_buffer(buf, data, new_frame); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_append_buffer(buf, data, new_frame); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_update_image(_sg_image_t* img, const sg_image_data* data) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_update_image(img, data); - #elif defined(SOKOL_METAL) - _sg_mtl_update_image(img, data); - #elif defined(SOKOL_D3D11) - _sg_d3d11_update_image(img, data); - #elif defined(SOKOL_WGPU) - _sg_wgpu_update_image(img, data); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_update_image(img, data); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_push_debug_group(const char* name) { - #if defined(SOKOL_METAL) - _sg_mtl_push_debug_group(name); - #else - _SOKOL_UNUSED(name); - #endif -} - -static inline void _sg_pop_debug_group(void) { - #if defined(SOKOL_METAL) - _sg_mtl_pop_debug_group(); - #endif -} - -// ██████ ██████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ -// -// >>pool -_SOKOL_PRIVATE void _sg_init_pool(_sg_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - // slot 0 is reserved for the 'invalid id', so bump the pool size by 1 - pool->size = num + 1; - pool->queue_top = 0; - // generation counters indexable by pool slot index, slot 0 is reserved - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*)_sg_malloc_clear(gen_ctrs_size); - // it's not a bug to only reserve 'num' here - pool->free_queue = (int*) _sg_malloc_clear(sizeof(int) * (size_t)num); - // never allocate the zero-th pool item since the invalid id is 0 - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -_SOKOL_PRIVATE void _sg_discard_pool(_sg_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _sg_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _sg_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -_SOKOL_PRIVATE int _sg_pool_alloc_index(_sg_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SG_INVALID_SLOT_INDEX; - } -} - -_SOKOL_PRIVATE void _sg_pool_free_index(_sg_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - // debug check against double-free - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -_SOKOL_PRIVATE void _sg_reset_slot(_sg_slot_t* slot) { - SOKOL_ASSERT(slot); - _sg_clear(slot, sizeof(_sg_slot_t)); -} - -_SOKOL_PRIVATE void _sg_reset_buffer_to_alloc_state(_sg_buffer_t* buf) { - SOKOL_ASSERT(buf); - _sg_slot_t slot = buf->slot; - _sg_clear(buf, sizeof(*buf)); - buf->slot = slot; - buf->slot.state = SG_RESOURCESTATE_ALLOC; -} - -_SOKOL_PRIVATE void _sg_reset_image_to_alloc_state(_sg_image_t* img) { - SOKOL_ASSERT(img); - _sg_slot_t slot = img->slot; - _sg_clear(img, sizeof(*img)); - img->slot = slot; - img->slot.state = SG_RESOURCESTATE_ALLOC; -} - -_SOKOL_PRIVATE void _sg_reset_sampler_to_alloc_state(_sg_sampler_t* smp) { - SOKOL_ASSERT(smp); - _sg_slot_t slot = smp->slot; - _sg_clear(smp, sizeof(*smp)); - smp->slot = slot; - smp->slot.state = SG_RESOURCESTATE_ALLOC; -} - -_SOKOL_PRIVATE void _sg_reset_shader_to_alloc_state(_sg_shader_t* shd) { - SOKOL_ASSERT(shd); - _sg_slot_t slot = shd->slot; - _sg_clear(shd, sizeof(*shd)); - shd->slot = slot; - shd->slot.state = SG_RESOURCESTATE_ALLOC; -} - -_SOKOL_PRIVATE void _sg_reset_pipeline_to_alloc_state(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip); - _sg_slot_t slot = pip->slot; - _sg_clear(pip, sizeof(*pip)); - pip->slot = slot; - pip->slot.state = SG_RESOURCESTATE_ALLOC; -} - -_SOKOL_PRIVATE void _sg_reset_attachments_to_alloc_state(_sg_attachments_t* atts) { - SOKOL_ASSERT(atts); - _sg_slot_t slot = atts->slot; - _sg_clear(atts, sizeof(*atts)); - atts->slot = slot; - atts->slot.state = SG_RESOURCESTATE_ALLOC; -} - -_SOKOL_PRIVATE void _sg_setup_pools(_sg_pools_t* p, const sg_desc* desc) { - SOKOL_ASSERT(p); - SOKOL_ASSERT(desc); - // note: the pools here will have an additional item, since slot 0 is reserved - SOKOL_ASSERT((desc->buffer_pool_size > 0) && (desc->buffer_pool_size < _SG_MAX_POOL_SIZE)); - _sg_init_pool(&p->buffer_pool, desc->buffer_pool_size); - size_t buffer_pool_byte_size = sizeof(_sg_buffer_t) * (size_t)p->buffer_pool.size; - p->buffers = (_sg_buffer_t*) _sg_malloc_clear(buffer_pool_byte_size); - - SOKOL_ASSERT((desc->image_pool_size > 0) && (desc->image_pool_size < _SG_MAX_POOL_SIZE)); - _sg_init_pool(&p->image_pool, desc->image_pool_size); - size_t image_pool_byte_size = sizeof(_sg_image_t) * (size_t)p->image_pool.size; - p->images = (_sg_image_t*) _sg_malloc_clear(image_pool_byte_size); - - SOKOL_ASSERT((desc->sampler_pool_size > 0) && (desc->sampler_pool_size < _SG_MAX_POOL_SIZE)); - _sg_init_pool(&p->sampler_pool, desc->sampler_pool_size); - size_t sampler_pool_byte_size = sizeof(_sg_sampler_t) * (size_t)p->sampler_pool.size; - p->samplers = (_sg_sampler_t*) _sg_malloc_clear(sampler_pool_byte_size); - - SOKOL_ASSERT((desc->shader_pool_size > 0) && (desc->shader_pool_size < _SG_MAX_POOL_SIZE)); - _sg_init_pool(&p->shader_pool, desc->shader_pool_size); - size_t shader_pool_byte_size = sizeof(_sg_shader_t) * (size_t)p->shader_pool.size; - p->shaders = (_sg_shader_t*) _sg_malloc_clear(shader_pool_byte_size); - - SOKOL_ASSERT((desc->pipeline_pool_size > 0) && (desc->pipeline_pool_size < _SG_MAX_POOL_SIZE)); - _sg_init_pool(&p->pipeline_pool, desc->pipeline_pool_size); - size_t pipeline_pool_byte_size = sizeof(_sg_pipeline_t) * (size_t)p->pipeline_pool.size; - p->pipelines = (_sg_pipeline_t*) _sg_malloc_clear(pipeline_pool_byte_size); - - SOKOL_ASSERT((desc->attachments_pool_size > 0) && (desc->attachments_pool_size < _SG_MAX_POOL_SIZE)); - _sg_init_pool(&p->attachments_pool, desc->attachments_pool_size); - size_t attachments_pool_byte_size = sizeof(_sg_attachments_t) * (size_t)p->attachments_pool.size; - p->attachments = (_sg_attachments_t*) _sg_malloc_clear(attachments_pool_byte_size); -} - -_SOKOL_PRIVATE void _sg_discard_pools(_sg_pools_t* p) { - SOKOL_ASSERT(p); - _sg_free(p->attachments); p->attachments = 0; - _sg_free(p->pipelines); p->pipelines = 0; - _sg_free(p->shaders); p->shaders = 0; - _sg_free(p->samplers); p->samplers = 0; - _sg_free(p->images); p->images = 0; - _sg_free(p->buffers); p->buffers = 0; - _sg_discard_pool(&p->attachments_pool); - _sg_discard_pool(&p->pipeline_pool); - _sg_discard_pool(&p->shader_pool); - _sg_discard_pool(&p->sampler_pool); - _sg_discard_pool(&p->image_pool); - _sg_discard_pool(&p->buffer_pool); -} - -/* allocate the slot at slot_index: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the resource id -*/ -_SOKOL_PRIVATE uint32_t _sg_slot_alloc(_sg_pool_t* pool, _sg_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(slot->id == SG_INVALID_ID); - SOKOL_ASSERT(slot->state == SG_RESOURCESTATE_INITIAL); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SG_SLOT_SHIFT)|(slot_index & _SG_SLOT_MASK); - slot->state = SG_RESOURCESTATE_ALLOC; - return slot->id; -} - -// extract slot index from id -_SOKOL_PRIVATE int _sg_slot_index(uint32_t id) { - int slot_index = (int) (id & _SG_SLOT_MASK); - SOKOL_ASSERT(_SG_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -// returns pointer to resource by id without matching id check -_SOKOL_PRIVATE _sg_buffer_t* _sg_buffer_at(const _sg_pools_t* p, uint32_t buf_id) { - SOKOL_ASSERT(p && (SG_INVALID_ID != buf_id)); - int slot_index = _sg_slot_index(buf_id); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->buffer_pool.size)); - return &p->buffers[slot_index]; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_image_at(const _sg_pools_t* p, uint32_t img_id) { - SOKOL_ASSERT(p && (SG_INVALID_ID != img_id)); - int slot_index = _sg_slot_index(img_id); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->image_pool.size)); - return &p->images[slot_index]; -} - -_SOKOL_PRIVATE _sg_sampler_t* _sg_sampler_at(const _sg_pools_t* p, uint32_t smp_id) { - SOKOL_ASSERT(p && (SG_INVALID_ID != smp_id)); - int slot_index = _sg_slot_index(smp_id); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->sampler_pool.size)); - return &p->samplers[slot_index]; -} - -_SOKOL_PRIVATE _sg_shader_t* _sg_shader_at(const _sg_pools_t* p, uint32_t shd_id) { - SOKOL_ASSERT(p && (SG_INVALID_ID != shd_id)); - int slot_index = _sg_slot_index(shd_id); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->shader_pool.size)); - return &p->shaders[slot_index]; -} - -_SOKOL_PRIVATE _sg_pipeline_t* _sg_pipeline_at(const _sg_pools_t* p, uint32_t pip_id) { - SOKOL_ASSERT(p && (SG_INVALID_ID != pip_id)); - int slot_index = _sg_slot_index(pip_id); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->pipeline_pool.size)); - return &p->pipelines[slot_index]; -} - -_SOKOL_PRIVATE _sg_attachments_t* _sg_attachments_at(const _sg_pools_t* p, uint32_t atts_id) { - SOKOL_ASSERT(p && (SG_INVALID_ID != atts_id)); - int slot_index = _sg_slot_index(atts_id); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->attachments_pool.size)); - return &p->attachments[slot_index]; -} - -// returns pointer to resource with matching id check, may return 0 -_SOKOL_PRIVATE _sg_buffer_t* _sg_lookup_buffer(const _sg_pools_t* p, uint32_t buf_id) { - if (SG_INVALID_ID != buf_id) { - _sg_buffer_t* buf = _sg_buffer_at(p, buf_id); - if (buf->slot.id == buf_id) { - return buf; - } - } - return 0; -} - -_SOKOL_PRIVATE _sg_image_t* _sg_lookup_image(const _sg_pools_t* p, uint32_t img_id) { - if (SG_INVALID_ID != img_id) { - _sg_image_t* img = _sg_image_at(p, img_id); - if (img->slot.id == img_id) { - return img; - } - } - return 0; -} - -_SOKOL_PRIVATE _sg_sampler_t* _sg_lookup_sampler(const _sg_pools_t* p, uint32_t smp_id) { - if (SG_INVALID_ID != smp_id) { - _sg_sampler_t* smp = _sg_sampler_at(p, smp_id); - if (smp->slot.id == smp_id) { - return smp; - } - } - return 0; -} - -_SOKOL_PRIVATE _sg_shader_t* _sg_lookup_shader(const _sg_pools_t* p, uint32_t shd_id) { - SOKOL_ASSERT(p); - if (SG_INVALID_ID != shd_id) { - _sg_shader_t* shd = _sg_shader_at(p, shd_id); - if (shd->slot.id == shd_id) { - return shd; - } - } - return 0; -} - -_SOKOL_PRIVATE _sg_pipeline_t* _sg_lookup_pipeline(const _sg_pools_t* p, uint32_t pip_id) { - SOKOL_ASSERT(p); - if (SG_INVALID_ID != pip_id) { - _sg_pipeline_t* pip = _sg_pipeline_at(p, pip_id); - if (pip->slot.id == pip_id) { - return pip; - } - } - return 0; -} - -_SOKOL_PRIVATE _sg_attachments_t* _sg_lookup_attachments(const _sg_pools_t* p, uint32_t atts_id) { - SOKOL_ASSERT(p); - if (SG_INVALID_ID != atts_id) { - _sg_attachments_t* atts = _sg_attachments_at(p, atts_id); - if (atts->slot.id == atts_id) { - return atts; - } - } - return 0; -} - -_SOKOL_PRIVATE void _sg_discard_all_resources(_sg_pools_t* p) { - /* this is a bit dumb since it loops over all pool slots to - find the occupied slots, on the other hand it is only ever - executed at shutdown - NOTE: ONLY EXECUTE THIS AT SHUTDOWN - ...because the free queues will not be reset - and the resource slots not be cleared! - */ - for (int i = 1; i < p->buffer_pool.size; i++) { - sg_resource_state state = p->buffers[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_buffer(&p->buffers[i]); - } - } - for (int i = 1; i < p->image_pool.size; i++) { - sg_resource_state state = p->images[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_image(&p->images[i]); - } - } - for (int i = 1; i < p->sampler_pool.size; i++) { - sg_resource_state state = p->samplers[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_sampler(&p->samplers[i]); - } - } - for (int i = 1; i < p->shader_pool.size; i++) { - sg_resource_state state = p->shaders[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_shader(&p->shaders[i]); - } - } - for (int i = 1; i < p->pipeline_pool.size; i++) { - sg_resource_state state = p->pipelines[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_pipeline(&p->pipelines[i]); - } - } - for (int i = 1; i < p->attachments_pool.size; i++) { - sg_resource_state state = p->attachments[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_attachments(&p->attachments[i]); - } - } -} - -// ██ ██ █████ ██ ██ ██████ █████ ████████ ██ ██████ ███ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ███████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ████ ██ ██ ███████ ██ ██████ ██ ██ ██ ██ ██████ ██ ████ -// -// >>validation -#if defined(SOKOL_DEBUG) -_SOKOL_PRIVATE void _sg_validate_begin(void) { - _sg.validate_error = SG_LOGITEM_OK; -} - -_SOKOL_PRIVATE bool _sg_validate_end(void) { - if (_sg.validate_error != SG_LOGITEM_OK) { - #if !defined(SOKOL_VALIDATE_NON_FATAL) - _SG_PANIC(VALIDATION_FAILED); - return false; - #else - return false; - #endif - } else { - return true; - } -} -#endif - -_SOKOL_PRIVATE bool _sg_validate_buffer_desc(const sg_buffer_desc* desc) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(desc); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT(desc); - _sg_validate_begin(); - _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_BUFFERDESC_CANARY); - _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_BUFFERDESC_CANARY); - _SG_VALIDATE(desc->size > 0, VALIDATE_BUFFERDESC_SIZE); - bool injected = (0 != desc->gl_buffers[0]) || - (0 != desc->mtl_buffers[0]) || - (0 != desc->d3d11_buffer) || - (0 != desc->wgpu_buffer); - if (!injected && (desc->usage == SG_USAGE_IMMUTABLE)) { - _SG_VALIDATE((0 != desc->data.ptr) && (desc->data.size > 0), VALIDATE_BUFFERDESC_DATA); - _SG_VALIDATE(desc->size == desc->data.size, VALIDATE_BUFFERDESC_DATA_SIZE); - } else { - _SG_VALIDATE(0 == desc->data.ptr, VALIDATE_BUFFERDESC_NO_DATA); - } - if (desc->type == SG_BUFFERTYPE_STORAGEBUFFER) { - _SG_VALIDATE(_sg.features.storage_buffer, VALIDATE_BUFFERDESC_STORAGEBUFFER_SUPPORTED); - _SG_VALIDATE(_sg_multiple_u64(desc->size, 4), VALIDATE_BUFFERDESC_STORAGEBUFFER_SIZE_MULTIPLE_4); - } - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE void _sg_validate_image_data(const sg_image_data* data, sg_pixel_format fmt, int width, int height, int num_faces, int num_mips, int num_slices) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(data); - _SOKOL_UNUSED(fmt); - _SOKOL_UNUSED(width); - _SOKOL_UNUSED(height); - _SOKOL_UNUSED(num_faces); - _SOKOL_UNUSED(num_mips); - _SOKOL_UNUSED(num_slices); - #else - for (int face_index = 0; face_index < num_faces; face_index++) { - for (int mip_index = 0; mip_index < num_mips; mip_index++) { - const bool has_data = data->subimage[face_index][mip_index].ptr != 0; - const bool has_size = data->subimage[face_index][mip_index].size > 0; - _SG_VALIDATE(has_data && has_size, VALIDATE_IMAGEDATA_NODATA); - const int mip_width = _sg_miplevel_dim(width, mip_index); - const int mip_height = _sg_miplevel_dim(height, mip_index); - const int bytes_per_slice = _sg_surface_pitch(fmt, mip_width, mip_height, 1); - const int expected_size = bytes_per_slice * num_slices; - _SG_VALIDATE(expected_size == (int)data->subimage[face_index][mip_index].size, VALIDATE_IMAGEDATA_DATA_SIZE); - } - } - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_image_desc(const sg_image_desc* desc) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(desc); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT(desc); - _sg_validate_begin(); - _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_IMAGEDESC_CANARY); - _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_IMAGEDESC_CANARY); - _SG_VALIDATE(desc->width > 0, VALIDATE_IMAGEDESC_WIDTH); - _SG_VALIDATE(desc->height > 0, VALIDATE_IMAGEDESC_HEIGHT); - const sg_pixel_format fmt = desc->pixel_format; - const sg_usage usage = desc->usage; - const bool injected = (0 != desc->gl_textures[0]) || - (0 != desc->mtl_textures[0]) || - (0 != desc->d3d11_texture) || - (0 != desc->wgpu_texture); - if (_sg_is_depth_or_depth_stencil_format(fmt)) { - _SG_VALIDATE(desc->type != SG_IMAGETYPE_3D, VALIDATE_IMAGEDESC_DEPTH_3D_IMAGE); - } - if (desc->render_target) { - SOKOL_ASSERT(((int)fmt >= 0) && ((int)fmt < _SG_PIXELFORMAT_NUM)); - _SG_VALIDATE(_sg.formats[fmt].render, VALIDATE_IMAGEDESC_RT_PIXELFORMAT); - _SG_VALIDATE(usage == SG_USAGE_IMMUTABLE, VALIDATE_IMAGEDESC_RT_IMMUTABLE); - _SG_VALIDATE(desc->data.subimage[0][0].ptr==0, VALIDATE_IMAGEDESC_RT_NO_DATA); - if (desc->sample_count > 1) { - _SG_VALIDATE(_sg.formats[fmt].msaa, VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT); - _SG_VALIDATE(desc->num_mipmaps == 1, VALIDATE_IMAGEDESC_MSAA_NUM_MIPMAPS); - _SG_VALIDATE(desc->type != SG_IMAGETYPE_3D, VALIDATE_IMAGEDESC_MSAA_3D_IMAGE); - } - } else { - _SG_VALIDATE(desc->sample_count == 1, VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT); - const bool valid_nonrt_fmt = !_sg_is_valid_rendertarget_depth_format(fmt); - _SG_VALIDATE(valid_nonrt_fmt, VALIDATE_IMAGEDESC_NONRT_PIXELFORMAT); - const bool is_compressed = _sg_is_compressed_pixel_format(desc->pixel_format); - const bool is_immutable = (usage == SG_USAGE_IMMUTABLE); - if (is_compressed) { - _SG_VALIDATE(is_immutable, VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE); - } - if (!injected && is_immutable) { - // image desc must have valid data - _sg_validate_image_data(&desc->data, - desc->pixel_format, - desc->width, - desc->height, - (desc->type == SG_IMAGETYPE_CUBE) ? 6 : 1, - desc->num_mipmaps, - desc->num_slices); - } else { - // image desc must not have data - for (int face_index = 0; face_index < SG_CUBEFACE_NUM; face_index++) { - for (int mip_index = 0; mip_index < SG_MAX_MIPMAPS; mip_index++) { - const bool no_data = 0 == desc->data.subimage[face_index][mip_index].ptr; - const bool no_size = 0 == desc->data.subimage[face_index][mip_index].size; - if (injected) { - _SG_VALIDATE(no_data && no_size, VALIDATE_IMAGEDESC_INJECTED_NO_DATA); - } - if (!is_immutable) { - _SG_VALIDATE(no_data && no_size, VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA); - } - } - } - } - } - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_sampler_desc(const sg_sampler_desc* desc) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(desc); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT(desc); - _sg_validate_begin(); - _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_SAMPLERDESC_CANARY); - _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_SAMPLERDESC_CANARY); - // restriction from WebGPU: when anisotropy > 1, all filters must be linear - if (desc->max_anisotropy > 1) { - _SG_VALIDATE((desc->min_filter == SG_FILTER_LINEAR) - && (desc->mag_filter == SG_FILTER_LINEAR) - && (desc->mipmap_filter == SG_FILTER_LINEAR), - VALIDATE_SAMPLERDESC_ANISTROPIC_REQUIRES_LINEAR_FILTERING); - } - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(desc); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT(desc); - _sg_validate_begin(); - _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_SHADERDESC_CANARY); - _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_SHADERDESC_CANARY); - #if defined(SOKOL_GLCORE) || defined(SOKOL_GLES3) || defined(SOKOL_WGPU) - // on GL or WebGPU, must provide shader source code - _SG_VALIDATE(0 != desc->vs.source, VALIDATE_SHADERDESC_SOURCE); - _SG_VALIDATE(0 != desc->fs.source, VALIDATE_SHADERDESC_SOURCE); - #elif defined(SOKOL_METAL) || defined(SOKOL_D3D11) - // on Metal or D3D11, must provide shader source code or byte code - _SG_VALIDATE((0 != desc->vs.source)||(0 != desc->vs.bytecode.ptr), VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE); - _SG_VALIDATE((0 != desc->fs.source)||(0 != desc->fs.bytecode.ptr), VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE); - #else - // Dummy Backend, don't require source or bytecode - #endif - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - if (desc->attrs[i].name) { - _SG_VALIDATE(strlen(desc->attrs[i].name) < _SG_STRING_SIZE, VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG); - } - if (desc->attrs[i].sem_name) { - _SG_VALIDATE(strlen(desc->attrs[i].sem_name) < _SG_STRING_SIZE, VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG); - } - } - // if shader byte code, the size must also be provided - if (0 != desc->vs.bytecode.ptr) { - _SG_VALIDATE(desc->vs.bytecode.size > 0, VALIDATE_SHADERDESC_NO_BYTECODE_SIZE); - } - if (0 != desc->fs.bytecode.ptr) { - _SG_VALIDATE(desc->fs.bytecode.size > 0, VALIDATE_SHADERDESC_NO_BYTECODE_SIZE); - } - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - const sg_shader_stage_desc* stage_desc = (stage_index == 0)? &desc->vs : &desc->fs; - bool uniform_blocks_continuous = true; - for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { - const sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index]; - if (ub_desc->size > 0) { - _SG_VALIDATE(uniform_blocks_continuous, VALIDATE_SHADERDESC_NO_CONT_UBS); - #if defined(_SOKOL_ANY_GL) - bool uniforms_continuous = true; - uint32_t uniform_offset = 0; - int num_uniforms = 0; - for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) { - const sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index]; - if (u_desc->type != SG_UNIFORMTYPE_INVALID) { - _SG_VALIDATE(uniforms_continuous, VALIDATE_SHADERDESC_NO_CONT_UB_MEMBERS); - #if defined(SOKOL_GLES3) - _SG_VALIDATE(0 != u_desc->name, VALIDATE_SHADERDESC_UB_MEMBER_NAME); - #endif - const int array_count = u_desc->array_count; - _SG_VALIDATE(array_count > 0, VALIDATE_SHADERDESC_UB_ARRAY_COUNT); - const uint32_t u_align = _sg_uniform_alignment(u_desc->type, array_count, ub_desc->layout); - const uint32_t u_size = _sg_uniform_size(u_desc->type, array_count, ub_desc->layout); - uniform_offset = _sg_align_u32(uniform_offset, u_align); - uniform_offset += u_size; - num_uniforms++; - // with std140, arrays are only allowed for FLOAT4, INT4, MAT4 - if (ub_desc->layout == SG_UNIFORMLAYOUT_STD140) { - if (array_count > 1) { - _SG_VALIDATE((u_desc->type == SG_UNIFORMTYPE_FLOAT4) || (u_desc->type == SG_UNIFORMTYPE_INT4) || (u_desc->type == SG_UNIFORMTYPE_MAT4), VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE); - } - } - } else { - uniforms_continuous = false; - } - } - if (ub_desc->layout == SG_UNIFORMLAYOUT_STD140) { - uniform_offset = _sg_align_u32(uniform_offset, 16); - } - _SG_VALIDATE((size_t)uniform_offset == ub_desc->size, VALIDATE_SHADERDESC_UB_SIZE_MISMATCH); - _SG_VALIDATE(num_uniforms > 0, VALIDATE_SHADERDESC_NO_UB_MEMBERS); - #endif - } else { - uniform_blocks_continuous = false; - } - } - bool storage_buffers_continuous = true; - for (int sbuf_index = 0; sbuf_index < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; sbuf_index++) { - const sg_shader_storage_buffer_desc* sbuf_desc = &stage_desc->storage_buffers[sbuf_index]; - if (sbuf_desc->used) { - _SG_VALIDATE(storage_buffers_continuous, VALIDATE_SHADERDESC_NO_CONT_STORAGEBUFFERS); - _SG_VALIDATE(sbuf_desc->readonly, VALIDATE_SHADERDESC_STORAGEBUFFER_READONLY); - } else { - storage_buffers_continuous = false; - } - } - bool images_continuous = true; - int num_images = 0; - for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { - const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; - if (img_desc->used) { - _SG_VALIDATE(images_continuous, VALIDATE_SHADERDESC_NO_CONT_IMAGES); - num_images++; - } else { - images_continuous = false; - } - } - bool samplers_continuous = true; - int num_samplers = 0; - for (int smp_index = 0; smp_index < SG_MAX_SHADERSTAGE_SAMPLERS; smp_index++) { - const sg_shader_sampler_desc* smp_desc = &stage_desc->samplers[smp_index]; - if (smp_desc->used) { - _SG_VALIDATE(samplers_continuous, VALIDATE_SHADERDESC_NO_CONT_SAMPLERS); - num_samplers++; - } else { - samplers_continuous = false; - } - } - bool image_samplers_continuous = true; - int num_image_samplers = 0; - for (int img_smp_index = 0; img_smp_index < SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS; img_smp_index++) { - const sg_shader_image_sampler_pair_desc* img_smp_desc = &stage_desc->image_sampler_pairs[img_smp_index]; - if (img_smp_desc->used) { - _SG_VALIDATE(image_samplers_continuous, VALIDATE_SHADERDESC_NO_CONT_IMAGE_SAMPLER_PAIRS); - num_image_samplers++; - const bool img_slot_in_range = (img_smp_desc->image_slot >= 0) && (img_smp_desc->image_slot < SG_MAX_SHADERSTAGE_IMAGES); - const bool smp_slot_in_range = (img_smp_desc->sampler_slot >= 0) && (img_smp_desc->sampler_slot < SG_MAX_SHADERSTAGE_SAMPLERS); - _SG_VALIDATE(img_slot_in_range && (img_smp_desc->image_slot < num_images), VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_IMAGE_SLOT_OUT_OF_RANGE); - _SG_VALIDATE(smp_slot_in_range && (img_smp_desc->sampler_slot < num_samplers), VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_IMAGE_SLOT_OUT_OF_RANGE); - #if defined(_SOKOL_ANY_GL) - _SG_VALIDATE(img_smp_desc->glsl_name != 0, VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_NAME_REQUIRED_FOR_GL); - #endif - if (img_slot_in_range && smp_slot_in_range) { - const sg_shader_image_desc* img_desc = &stage_desc->images[img_smp_desc->image_slot]; - const sg_shader_sampler_desc* smp_desc = &stage_desc->samplers[img_smp_desc->sampler_slot]; - const bool needs_nonfiltering = (img_desc->sample_type == SG_IMAGESAMPLETYPE_UINT) - || (img_desc->sample_type == SG_IMAGESAMPLETYPE_SINT) - || (img_desc->sample_type == SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT); - const bool needs_comparison = img_desc->sample_type == SG_IMAGESAMPLETYPE_DEPTH; - if (needs_nonfiltering) { - _SG_VALIDATE(needs_nonfiltering && (smp_desc->sampler_type == SG_SAMPLERTYPE_NONFILTERING), VALIDATE_SHADERDESC_NONFILTERING_SAMPLER_REQUIRED); - } - if (needs_comparison) { - _SG_VALIDATE(needs_comparison && (smp_desc->sampler_type == SG_SAMPLERTYPE_COMPARISON), VALIDATE_SHADERDESC_COMPARISON_SAMPLER_REQUIRED); - } - } - } else { - _SG_VALIDATE(img_smp_desc->glsl_name == 0, VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_HAS_NAME_BUT_NOT_USED); - _SG_VALIDATE(img_smp_desc->image_slot == 0, VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_HAS_IMAGE_BUT_NOT_USED); - _SG_VALIDATE(img_smp_desc->sampler_slot == 0, VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_HAS_SAMPLER_BUT_NOT_USED); - image_samplers_continuous = false; - } - } - // each image and sampler must be referenced by an image sampler - const uint32_t expected_img_slot_mask = (uint32_t)((1 << num_images) - 1); - const uint32_t expected_smp_slot_mask = (uint32_t)((1 << num_samplers) - 1); - uint32_t actual_img_slot_mask = 0; - uint32_t actual_smp_slot_mask = 0; - for (int img_smp_index = 0; img_smp_index < num_image_samplers; img_smp_index++) { - const sg_shader_image_sampler_pair_desc* img_smp_desc = &stage_desc->image_sampler_pairs[img_smp_index]; - actual_img_slot_mask |= (1 << ((uint32_t)img_smp_desc->image_slot & 31)); - actual_smp_slot_mask |= (1 << ((uint32_t)img_smp_desc->sampler_slot & 31)); - } - _SG_VALIDATE(expected_img_slot_mask == actual_img_slot_mask, VALIDATE_SHADERDESC_IMAGE_NOT_REFERENCED_BY_IMAGE_SAMPLER_PAIRS); - _SG_VALIDATE(expected_smp_slot_mask == actual_smp_slot_mask, VALIDATE_SHADERDESC_SAMPLER_NOT_REFERENCED_BY_IMAGE_SAMPLER_PAIRS); - } - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_pipeline_desc(const sg_pipeline_desc* desc) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(desc); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT(desc); - _sg_validate_begin(); - _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_PIPELINEDESC_CANARY); - _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_PIPELINEDESC_CANARY); - _SG_VALIDATE(desc->shader.id != SG_INVALID_ID, VALIDATE_PIPELINEDESC_SHADER); - for (int buf_index = 0; buf_index < SG_MAX_VERTEX_BUFFERS; buf_index++) { - const sg_vertex_buffer_layout_state* l_state = &desc->layout.buffers[buf_index]; - if (l_state->stride == 0) { - continue; - } - _SG_VALIDATE(_sg_multiple_u64((uint64_t)l_state->stride, 4), VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4); - } - const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, desc->shader.id); - _SG_VALIDATE(0 != shd, VALIDATE_PIPELINEDESC_SHADER); - if (shd) { - _SG_VALIDATE(shd->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_PIPELINEDESC_SHADER); - bool attrs_cont = true; - for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { - const sg_vertex_attr_state* a_state = &desc->layout.attrs[attr_index]; - if (a_state->format == SG_VERTEXFORMAT_INVALID) { - attrs_cont = false; - continue; - } - _SG_VALIDATE(attrs_cont, VALIDATE_PIPELINEDESC_NO_CONT_ATTRS); - SOKOL_ASSERT(a_state->buffer_index < SG_MAX_VERTEX_BUFFERS); - #if defined(SOKOL_D3D11) - // on D3D11, semantic names (and semantic indices) must be provided - _SG_VALIDATE(!_sg_strempty(&shd->d3d11.attrs[attr_index].sem_name), VALIDATE_PIPELINEDESC_ATTR_SEMANTICS); - #endif - } - } - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_attachments_desc(const sg_attachments_desc* desc) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(desc); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT(desc); - _sg_validate_begin(); - _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_ATTACHMENTSDESC_CANARY); - _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_ATTACHMENTSDESC_CANARY); - bool atts_cont = true; - int color_width = -1, color_height = -1, color_sample_count = -1; - bool has_color_atts = false; - for (int att_index = 0; att_index < SG_MAX_COLOR_ATTACHMENTS; att_index++) { - const sg_attachment_desc* att = &desc->colors[att_index]; - if (att->image.id == SG_INVALID_ID) { - atts_cont = false; - continue; - } - _SG_VALIDATE(atts_cont, VALIDATE_ATTACHMENTSDESC_NO_CONT_COLOR_ATTS); - has_color_atts = true; - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, att->image.id); - _SG_VALIDATE(img, VALIDATE_ATTACHMENTSDESC_IMAGE); - if (0 != img) { - _SG_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_ATTACHMENTSDESC_IMAGE); - _SG_VALIDATE(img->cmn.render_target, VALIDATE_ATTACHMENTSDESC_IMAGE_NO_RT); - _SG_VALIDATE(att->mip_level < img->cmn.num_mipmaps, VALIDATE_ATTACHMENTSDESC_MIPLEVEL); - if (img->cmn.type == SG_IMAGETYPE_CUBE) { - _SG_VALIDATE(att->slice < 6, VALIDATE_ATTACHMENTSDESC_FACE); - } else if (img->cmn.type == SG_IMAGETYPE_ARRAY) { - _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_LAYER); - } else if (img->cmn.type == SG_IMAGETYPE_3D) { - _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_SLICE); - } - if (att_index == 0) { - color_width = _sg_miplevel_dim(img->cmn.width, att->mip_level); - color_height = _sg_miplevel_dim(img->cmn.height, att->mip_level); - color_sample_count = img->cmn.sample_count; - } else { - _SG_VALIDATE(color_width == _sg_miplevel_dim(img->cmn.width, att->mip_level), VALIDATE_ATTACHMENTSDESC_IMAGE_SIZES); - _SG_VALIDATE(color_height == _sg_miplevel_dim(img->cmn.height, att->mip_level), VALIDATE_ATTACHMENTSDESC_IMAGE_SIZES); - _SG_VALIDATE(color_sample_count == img->cmn.sample_count, VALIDATE_ATTACHMENTSDESC_IMAGE_SAMPLE_COUNTS); - } - _SG_VALIDATE(_sg_is_valid_rendertarget_color_format(img->cmn.pixel_format), VALIDATE_ATTACHMENTSDESC_COLOR_INV_PIXELFORMAT); - - // check resolve attachment - const sg_attachment_desc* res_att = &desc->resolves[att_index]; - if (res_att->image.id != SG_INVALID_ID) { - // associated color attachment must be MSAA - _SG_VALIDATE(img->cmn.sample_count > 1, VALIDATE_ATTACHMENTSDESC_RESOLVE_COLOR_IMAGE_MSAA); - const _sg_image_t* res_img = _sg_lookup_image(&_sg.pools, res_att->image.id); - _SG_VALIDATE(res_img, VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE); - if (res_img != 0) { - _SG_VALIDATE(res_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE); - _SG_VALIDATE(res_img->cmn.render_target, VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_NO_RT); - _SG_VALIDATE(res_img->cmn.sample_count == 1, VALIDATE_ATTACHMENTSDESC_RESOLVE_SAMPLE_COUNT); - _SG_VALIDATE(res_att->mip_level < res_img->cmn.num_mipmaps, VALIDATE_ATTACHMENTSDESC_RESOLVE_MIPLEVEL); - if (res_img->cmn.type == SG_IMAGETYPE_CUBE) { - _SG_VALIDATE(res_att->slice < 6, VALIDATE_ATTACHMENTSDESC_RESOLVE_FACE); - } else if (res_img->cmn.type == SG_IMAGETYPE_ARRAY) { - _SG_VALIDATE(res_att->slice < res_img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_RESOLVE_LAYER); - } else if (res_img->cmn.type == SG_IMAGETYPE_3D) { - _SG_VALIDATE(res_att->slice < res_img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_RESOLVE_SLICE); - } - _SG_VALIDATE(img->cmn.pixel_format == res_img->cmn.pixel_format, VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_FORMAT); - _SG_VALIDATE(color_width == _sg_miplevel_dim(res_img->cmn.width, res_att->mip_level), VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES); - _SG_VALIDATE(color_height == _sg_miplevel_dim(res_img->cmn.height, res_att->mip_level), VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES); - } - } - } - } - bool has_depth_stencil_att = false; - if (desc->depth_stencil.image.id != SG_INVALID_ID) { - const sg_attachment_desc* att = &desc->depth_stencil; - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, att->image.id); - _SG_VALIDATE(img, VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE); - has_depth_stencil_att = true; - if (img) { - _SG_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE); - _SG_VALIDATE(att->mip_level < img->cmn.num_mipmaps, VALIDATE_ATTACHMENTSDESC_DEPTH_MIPLEVEL); - if (img->cmn.type == SG_IMAGETYPE_CUBE) { - _SG_VALIDATE(att->slice < 6, VALIDATE_ATTACHMENTSDESC_DEPTH_FACE); - } else if (img->cmn.type == SG_IMAGETYPE_ARRAY) { - _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_DEPTH_LAYER); - } else if (img->cmn.type == SG_IMAGETYPE_3D) { - // NOTE: this can't actually happen because of VALIDATE_IMAGEDESC_DEPTH_3D_IMAGE - _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_DEPTH_SLICE); - } - _SG_VALIDATE(img->cmn.render_target, VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_NO_RT); - _SG_VALIDATE((color_width == -1) || (color_width == _sg_miplevel_dim(img->cmn.width, att->mip_level)), VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES); - _SG_VALIDATE((color_height == -1) || (color_height == _sg_miplevel_dim(img->cmn.height, att->mip_level)), VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES); - _SG_VALIDATE((color_sample_count == -1) || (color_sample_count == img->cmn.sample_count), VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SAMPLE_COUNT); - _SG_VALIDATE(_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format), VALIDATE_ATTACHMENTSDESC_DEPTH_INV_PIXELFORMAT); - } - } - _SG_VALIDATE(has_color_atts || has_depth_stencil_att, VALIDATE_ATTACHMENTSDESC_NO_ATTACHMENTS); - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_begin_pass(const sg_pass* pass) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(pass); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - _sg_validate_begin(); - _SG_VALIDATE(pass->_start_canary == 0, VALIDATE_BEGINPASS_CANARY); - _SG_VALIDATE(pass->_end_canary == 0, VALIDATE_BEGINPASS_CANARY); - if (pass->attachments.id == SG_INVALID_ID) { - // this is a swapchain pass - _SG_VALIDATE(pass->swapchain.width > 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH); - _SG_VALIDATE(pass->swapchain.height > 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_HEIGHT); - _SG_VALIDATE(pass->swapchain.sample_count > 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_SAMPLECOUNT); - _SG_VALIDATE(pass->swapchain.color_format > SG_PIXELFORMAT_NONE, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_COLORFORMAT); - // NOTE: depth buffer is optional, so depth_format is allowed to be invalid - // NOTE: the GL framebuffer handle may actually be 0 - #if defined(SOKOL_METAL) - _SG_VALIDATE(pass->swapchain.metal.current_drawable != 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_CURRENTDRAWABLE); - if (pass->swapchain.depth_format == SG_PIXELFORMAT_NONE) { - _SG_VALIDATE(pass->swapchain.metal.depth_stencil_texture == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE_NOTSET); - } else { - _SG_VALIDATE(pass->swapchain.metal.depth_stencil_texture != 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE); - } - if (pass->swapchain.sample_count > 1) { - _SG_VALIDATE(pass->swapchain.metal.msaa_color_texture != 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE); - } else { - _SG_VALIDATE(pass->swapchain.metal.msaa_color_texture == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE_NOTSET); - } - #elif defined(SOKOL_D3D11) - _SG_VALIDATE(pass->swapchain.d3d11.render_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RENDERVIEW); - if (pass->swapchain.depth_format == SG_PIXELFORMAT_NONE) { - _SG_VALIDATE(pass->swapchain.d3d11.depth_stencil_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW_NOTSET); - } else { - _SG_VALIDATE(pass->swapchain.d3d11.depth_stencil_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW); - } - if (pass->swapchain.sample_count > 1) { - _SG_VALIDATE(pass->swapchain.d3d11.resolve_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW); - } else { - _SG_VALIDATE(pass->swapchain.d3d11.resolve_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW_NOTSET); - } - #elif defined(SOKOL_WGPU) - _SG_VALIDATE(pass->swapchain.wgpu.render_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RENDERVIEW); - if (pass->swapchain.depth_format == SG_PIXELFORMAT_NONE) { - _SG_VALIDATE(pass->swapchain.wgpu.depth_stencil_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW_NOTSET); - } else { - _SG_VALIDATE(pass->swapchain.wgpu.depth_stencil_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW); - } - if (pass->swapchain.sample_count > 1) { - _SG_VALIDATE(pass->swapchain.wgpu.resolve_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW); - } else { - _SG_VALIDATE(pass->swapchain.wgpu.resolve_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW_NOTSET); - } - #endif - } else { - // this is an 'offscreen pass' - const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, pass->attachments.id); - if (atts) { - _SG_VALIDATE(atts->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_ATTACHMENTS_VALID); - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - const _sg_attachment_common_t* color_att = &atts->cmn.colors[i]; - const _sg_image_t* color_img = _sg_attachments_color_image(atts, i); - if (color_img) { - _SG_VALIDATE(color_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE); - _SG_VALIDATE(color_img->slot.id == color_att->image_id.id, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE); - } - const _sg_attachment_common_t* resolve_att = &atts->cmn.resolves[i]; - const _sg_image_t* resolve_img = _sg_attachments_resolve_image(atts, i); - if (resolve_img) { - _SG_VALIDATE(resolve_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE); - _SG_VALIDATE(resolve_img->slot.id == resolve_att->image_id.id, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE); - } - } - const _sg_image_t* ds_img = _sg_attachments_ds_image(atts); - if (ds_img) { - const _sg_attachment_common_t* att = &atts->cmn.depth_stencil; - _SG_VALIDATE(ds_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE); - _SG_VALIDATE(ds_img->slot.id == att->image_id.id, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE); - } - } else { - _SG_VALIDATE(atts != 0, VALIDATE_BEGINPASS_ATTACHMENTS_EXISTS); - } - // swapchain params must be all zero! - _SG_VALIDATE(pass->swapchain.width == 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH_NOTSET); - _SG_VALIDATE(pass->swapchain.height == 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_HEIGHT_NOTSET); - _SG_VALIDATE(pass->swapchain.sample_count == 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_SAMPLECOUNT_NOTSET); - _SG_VALIDATE(pass->swapchain.color_format == _SG_PIXELFORMAT_DEFAULT, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_COLORFORMAT_NOTSET); - _SG_VALIDATE(pass->swapchain.depth_format == _SG_PIXELFORMAT_DEFAULT, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_DEPTHFORMAT_NOTSET); - #if defined(SOKOL_METAL) - _SG_VALIDATE(pass->swapchain.metal.current_drawable == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_CURRENTDRAWABLE_NOTSET); - _SG_VALIDATE(pass->swapchain.metal.depth_stencil_texture == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE_NOTSET); - _SG_VALIDATE(pass->swapchain.metal.msaa_color_texture == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE_NOTSET); - #elif defined(SOKOL_D3D11) - _SG_VALIDATE(pass->swapchain.d3d11.render_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RENDERVIEW_NOTSET); - _SG_VALIDATE(pass->swapchain.d3d11.depth_stencil_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW_NOTSET); - _SG_VALIDATE(pass->swapchain.d3d11.resolve_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW_NOTSET); - #elif defined(SOKOL_WGPU) - _SG_VALIDATE(pass->swapchain.wgpu.render_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RENDERVIEW_NOTSET); - _SG_VALIDATE(pass->swapchain.wgpu.depth_stencil_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW_NOTSET); - _SG_VALIDATE(pass->swapchain.wgpu.resolve_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW_NOTSET); - #elif defined(_SOKOL_ANY_GL) - _SG_VALIDATE(pass->swapchain.gl.framebuffer == 0, VALIDATE_BEGINPASS_SWAPCHAIN_GL_EXPECT_FRAMEBUFFER_NOTSET); - #endif - } - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_apply_pipeline(sg_pipeline pip_id) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(pip_id); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - _sg_validate_begin(); - // the pipeline object must be alive and valid - _SG_VALIDATE(pip_id.id != SG_INVALID_ID, VALIDATE_APIP_PIPELINE_VALID_ID); - const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - _SG_VALIDATE(pip != 0, VALIDATE_APIP_PIPELINE_EXISTS); - if (!pip) { - return _sg_validate_end(); - } - _SG_VALIDATE(pip->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_APIP_PIPELINE_VALID); - // the pipeline's shader must be alive and valid - SOKOL_ASSERT(pip->shader); - _SG_VALIDATE(pip->shader->slot.id == pip->cmn.shader_id.id, VALIDATE_APIP_SHADER_EXISTS); - _SG_VALIDATE(pip->shader->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_APIP_SHADER_VALID); - // check that pipeline attributes match current pass attributes - if (_sg.cur_pass.atts_id.id != SG_INVALID_ID) { - // an offscreen pass - const _sg_attachments_t* atts = _sg.cur_pass.atts; - SOKOL_ASSERT(atts); - _SG_VALIDATE(atts->slot.id == _sg.cur_pass.atts_id.id, VALIDATE_APIP_CURPASS_ATTACHMENTS_EXISTS); - _SG_VALIDATE(atts->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_APIP_CURPASS_ATTACHMENTS_VALID); - - _SG_VALIDATE(pip->cmn.color_count == atts->cmn.num_colors, VALIDATE_APIP_ATT_COUNT); - for (int i = 0; i < pip->cmn.color_count; i++) { - const _sg_image_t* att_img = _sg_attachments_color_image(atts, i); - _SG_VALIDATE(pip->cmn.colors[i].pixel_format == att_img->cmn.pixel_format, VALIDATE_APIP_COLOR_FORMAT); - _SG_VALIDATE(pip->cmn.sample_count == att_img->cmn.sample_count, VALIDATE_APIP_SAMPLE_COUNT); - } - const _sg_image_t* att_dsimg = _sg_attachments_ds_image(atts); - if (att_dsimg) { - _SG_VALIDATE(pip->cmn.depth.pixel_format == att_dsimg->cmn.pixel_format, VALIDATE_APIP_DEPTH_FORMAT); - } else { - _SG_VALIDATE(pip->cmn.depth.pixel_format == SG_PIXELFORMAT_NONE, VALIDATE_APIP_DEPTH_FORMAT); - } - } else { - // default pass - _SG_VALIDATE(pip->cmn.color_count == 1, VALIDATE_APIP_ATT_COUNT); - _SG_VALIDATE(pip->cmn.colors[0].pixel_format == _sg.cur_pass.swapchain.color_fmt, VALIDATE_APIP_COLOR_FORMAT); - _SG_VALIDATE(pip->cmn.depth.pixel_format == _sg.cur_pass.swapchain.depth_fmt, VALIDATE_APIP_DEPTH_FORMAT); - _SG_VALIDATE(pip->cmn.sample_count == _sg.cur_pass.swapchain.sample_count, VALIDATE_APIP_SAMPLE_COUNT); - } - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_apply_bindings(const sg_bindings* bindings) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(bindings); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - _sg_validate_begin(); - - // a pipeline object must have been applied - _SG_VALIDATE(_sg.cur_pipeline.id != SG_INVALID_ID, VALIDATE_ABND_PIPELINE); - const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, _sg.cur_pipeline.id); - _SG_VALIDATE(pip != 0, VALIDATE_ABND_PIPELINE_EXISTS); - if (!pip) { - return _sg_validate_end(); - } - _SG_VALIDATE(pip->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_ABND_PIPELINE_VALID); - SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); - - // has expected vertex buffers, and vertex buffers still exist - for (int i = 0; i < SG_MAX_VERTEX_BUFFERS; i++) { - if (bindings->vertex_buffers[i].id != SG_INVALID_ID) { - _SG_VALIDATE(pip->cmn.vertex_buffer_layout_active[i], VALIDATE_ABND_VBS); - // buffers in vertex-buffer-slots must be of type SG_BUFFERTYPE_VERTEXBUFFER - const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, bindings->vertex_buffers[i].id); - _SG_VALIDATE(buf != 0, VALIDATE_ABND_VB_EXISTS); - if (buf && buf->slot.state == SG_RESOURCESTATE_VALID) { - _SG_VALIDATE(SG_BUFFERTYPE_VERTEXBUFFER == buf->cmn.type, VALIDATE_ABND_VB_TYPE); - _SG_VALIDATE(!buf->cmn.append_overflow, VALIDATE_ABND_VB_OVERFLOW); - } - } else { - // vertex buffer provided in a slot which has no vertex layout in pipeline - _SG_VALIDATE(!pip->cmn.vertex_buffer_layout_active[i], VALIDATE_ABND_VBS); - } - } - - // index buffer expected or not, and index buffer still exists - if (pip->cmn.index_type == SG_INDEXTYPE_NONE) { - // pipeline defines non-indexed rendering, but index buffer provided - _SG_VALIDATE(bindings->index_buffer.id == SG_INVALID_ID, VALIDATE_ABND_IB); - } else { - // pipeline defines indexed rendering, but no index buffer provided - _SG_VALIDATE(bindings->index_buffer.id != SG_INVALID_ID, VALIDATE_ABND_NO_IB); - } - if (bindings->index_buffer.id != SG_INVALID_ID) { - // buffer in index-buffer-slot must be of type SG_BUFFERTYPE_INDEXBUFFER - const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, bindings->index_buffer.id); - _SG_VALIDATE(buf != 0, VALIDATE_ABND_IB_EXISTS); - if (buf && buf->slot.state == SG_RESOURCESTATE_VALID) { - _SG_VALIDATE(SG_BUFFERTYPE_INDEXBUFFER == buf->cmn.type, VALIDATE_ABND_IB_TYPE); - _SG_VALIDATE(!buf->cmn.append_overflow, VALIDATE_ABND_IB_OVERFLOW); - } - } - - // has expected vertex shader images - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { - const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_VS]; - if (stage->images[i].image_type != _SG_IMAGETYPE_DEFAULT) { - _SG_VALIDATE(bindings->vs.images[i].id != SG_INVALID_ID, VALIDATE_ABND_VS_EXPECTED_IMAGE_BINDING); - if (bindings->vs.images[i].id != SG_INVALID_ID) { - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, bindings->vs.images[i].id); - _SG_VALIDATE(img != 0, VALIDATE_ABND_VS_IMG_EXISTS); - if (img && img->slot.state == SG_RESOURCESTATE_VALID) { - _SG_VALIDATE(img->cmn.type == stage->images[i].image_type, VALIDATE_ABND_VS_IMAGE_TYPE_MISMATCH); - _SG_VALIDATE(img->cmn.sample_count == 1, VALIDATE_ABND_VS_IMAGE_MSAA); - const _sg_pixelformat_info_t* info = &_sg.formats[img->cmn.pixel_format]; - switch (stage->images[i].sample_type) { - case SG_IMAGESAMPLETYPE_FLOAT: - _SG_VALIDATE(info->filter, VALIDATE_ABND_VS_EXPECTED_FILTERABLE_IMAGE); - break; - case SG_IMAGESAMPLETYPE_DEPTH: - _SG_VALIDATE(info->depth, VALIDATE_ABND_VS_EXPECTED_DEPTH_IMAGE); - break; - default: - break; - } - } - } - } else { - _SG_VALIDATE(bindings->vs.images[i].id == SG_INVALID_ID, VALIDATE_ABND_VS_UNEXPECTED_IMAGE_BINDING); - } - } - - // has expected vertex shader image samplers - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++) { - const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_VS]; - if (stage->samplers[i].sampler_type != _SG_SAMPLERTYPE_DEFAULT) { - _SG_VALIDATE(bindings->vs.samplers[i].id != SG_INVALID_ID, VALIDATE_ABND_VS_EXPECTED_SAMPLER_BINDING); - if (bindings->vs.samplers[i].id != SG_INVALID_ID) { - const _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, bindings->vs.samplers[i].id); - _SG_VALIDATE(smp != 0, VALIDATE_ABND_VS_SMP_EXISTS); - if (smp) { - if (stage->samplers[i].sampler_type == SG_SAMPLERTYPE_COMPARISON) { - _SG_VALIDATE(smp->cmn.compare != SG_COMPAREFUNC_NEVER, VALIDATE_ABND_VS_UNEXPECTED_SAMPLER_COMPARE_NEVER); - } else { - _SG_VALIDATE(smp->cmn.compare == SG_COMPAREFUNC_NEVER, VALIDATE_ABND_VS_EXPECTED_SAMPLER_COMPARE_NEVER); - } - if (stage->samplers[i].sampler_type == SG_SAMPLERTYPE_NONFILTERING) { - const bool nonfiltering = (smp->cmn.min_filter != SG_FILTER_LINEAR) - && (smp->cmn.mag_filter != SG_FILTER_LINEAR) - && (smp->cmn.mipmap_filter != SG_FILTER_LINEAR); - _SG_VALIDATE(nonfiltering, VALIDATE_ABND_VS_EXPECTED_NONFILTERING_SAMPLER); - } - } - } - } else { - _SG_VALIDATE(bindings->vs.samplers[i].id == SG_INVALID_ID, VALIDATE_ABND_VS_UNEXPECTED_SAMPLER_BINDING); - } - } - - // has expected vertex shader storage buffers - for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { - const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_VS]; - if (stage->storage_buffers[i].used) { - _SG_VALIDATE(bindings->vs.storage_buffers[i].id != SG_INVALID_ID, VALIDATE_ABND_VS_EXPECTED_STORAGEBUFFER_BINDING); - if (bindings->vs.storage_buffers[i].id != SG_INVALID_ID) { - const _sg_buffer_t* sbuf = _sg_lookup_buffer(&_sg.pools, bindings->vs.storage_buffers[i].id); - _SG_VALIDATE(sbuf != 0, VALIDATE_ABND_VS_STORAGEBUFFER_EXISTS); - if (sbuf) { - _SG_VALIDATE(sbuf->cmn.type == SG_BUFFERTYPE_STORAGEBUFFER, VALIDATE_ABND_VS_STORAGEBUFFER_BINDING_BUFFERTYPE); - } - } - } else { - _SG_VALIDATE(bindings->vs.storage_buffers[i].id == SG_INVALID_ID, VALIDATE_ABND_VS_UNEXPECTED_STORAGEBUFFER_BINDING); - } - } - - // has expected fragment shader images - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { - const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_FS]; - if (stage->images[i].image_type != _SG_IMAGETYPE_DEFAULT) { - _SG_VALIDATE(bindings->fs.images[i].id != SG_INVALID_ID, VALIDATE_ABND_FS_EXPECTED_IMAGE_BINDING); - if (bindings->fs.images[i].id != SG_INVALID_ID) { - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, bindings->fs.images[i].id); - _SG_VALIDATE(img != 0, VALIDATE_ABND_FS_IMG_EXISTS); - if (img && img->slot.state == SG_RESOURCESTATE_VALID) { - _SG_VALIDATE(img->cmn.type == stage->images[i].image_type, VALIDATE_ABND_FS_IMAGE_TYPE_MISMATCH); - _SG_VALIDATE(img->cmn.sample_count == 1, VALIDATE_ABND_FS_IMAGE_MSAA); - const _sg_pixelformat_info_t* info = &_sg.formats[img->cmn.pixel_format]; - switch (stage->images[i].sample_type) { - case SG_IMAGESAMPLETYPE_FLOAT: - _SG_VALIDATE(info->filter, VALIDATE_ABND_FS_EXPECTED_FILTERABLE_IMAGE); - break; - case SG_IMAGESAMPLETYPE_DEPTH: - _SG_VALIDATE(info->depth, VALIDATE_ABND_FS_EXPECTED_DEPTH_IMAGE); - break; - default: - break; - } - } - } - } else { - _SG_VALIDATE(bindings->fs.images[i].id == SG_INVALID_ID, VALIDATE_ABND_FS_UNEXPECTED_IMAGE_BINDING); - } - } - - // has expected fragment shader samplers - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++) { - const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_FS]; - if (stage->samplers[i].sampler_type != _SG_SAMPLERTYPE_DEFAULT) { - _SG_VALIDATE(bindings->fs.samplers[i].id != SG_INVALID_ID, VALIDATE_ABND_FS_EXPECTED_SAMPLER_BINDING); - if (bindings->fs.samplers[i].id != SG_INVALID_ID) { - const _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, bindings->fs.samplers[i].id); - _SG_VALIDATE(smp != 0, VALIDATE_ABND_FS_SMP_EXISTS); - if (smp) { - if (stage->samplers[i].sampler_type == SG_SAMPLERTYPE_COMPARISON) { - _SG_VALIDATE(smp->cmn.compare != SG_COMPAREFUNC_NEVER, VALIDATE_ABND_FS_UNEXPECTED_SAMPLER_COMPARE_NEVER); - } else { - _SG_VALIDATE(smp->cmn.compare == SG_COMPAREFUNC_NEVER, VALIDATE_ABND_FS_EXPECTED_SAMPLER_COMPARE_NEVER); - } - if (stage->samplers[i].sampler_type == SG_SAMPLERTYPE_NONFILTERING) { - const bool nonfiltering = (smp->cmn.min_filter != SG_FILTER_LINEAR) - && (smp->cmn.mag_filter != SG_FILTER_LINEAR) - && (smp->cmn.mipmap_filter != SG_FILTER_LINEAR); - _SG_VALIDATE(nonfiltering, VALIDATE_ABND_FS_EXPECTED_NONFILTERING_SAMPLER); - } - } - } - } else { - _SG_VALIDATE(bindings->fs.samplers[i].id == SG_INVALID_ID, VALIDATE_ABND_FS_UNEXPECTED_SAMPLER_BINDING); - } - } - - // has expected fragment shader storage buffers - for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { - const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_FS]; - if (stage->storage_buffers[i].used) { - _SG_VALIDATE(bindings->fs.storage_buffers[i].id != SG_INVALID_ID, VALIDATE_ABND_FS_EXPECTED_STORAGEBUFFER_BINDING); - if (bindings->fs.storage_buffers[i].id != SG_INVALID_ID) { - const _sg_buffer_t* sbuf = _sg_lookup_buffer(&_sg.pools, bindings->fs.storage_buffers[i].id); - _SG_VALIDATE(sbuf != 0, VALIDATE_ABND_FS_STORAGEBUFFER_EXISTS); - if (sbuf) { - _SG_VALIDATE(sbuf->cmn.type == SG_BUFFERTYPE_STORAGEBUFFER, VALIDATE_ABND_FS_STORAGEBUFFER_BINDING_BUFFERTYPE); - } - } - } else { - _SG_VALIDATE(bindings->fs.storage_buffers[i].id == SG_INVALID_ID, VALIDATE_ABND_FS_UNEXPECTED_STORAGEBUFFER_BINDING); - } - } - - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(stage_index); - _SOKOL_UNUSED(ub_index); - _SOKOL_UNUSED(data); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT((stage_index == SG_SHADERSTAGE_VS) || (stage_index == SG_SHADERSTAGE_FS)); - SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); - _sg_validate_begin(); - _SG_VALIDATE(_sg.cur_pipeline.id != SG_INVALID_ID, VALIDATE_AUB_NO_PIPELINE); - const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, _sg.cur_pipeline.id); - SOKOL_ASSERT(pip && (pip->slot.id == _sg.cur_pipeline.id)); - SOKOL_ASSERT(pip->shader && (pip->shader->slot.id == pip->cmn.shader_id.id)); - - // check that there is a uniform block at 'stage' and 'ub_index' - const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[stage_index]; - _SG_VALIDATE(ub_index < stage->num_uniform_blocks, VALIDATE_AUB_NO_UB_AT_SLOT); - - // check that the provided data size matches the uniform block size - _SG_VALIDATE(data->size == stage->uniform_blocks[ub_index].size, VALIDATE_AUB_SIZE); - - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_update_buffer(const _sg_buffer_t* buf, const sg_range* data) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(buf); - _SOKOL_UNUSED(data); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT(buf && data && data->ptr); - _sg_validate_begin(); - _SG_VALIDATE(buf->cmn.usage != SG_USAGE_IMMUTABLE, VALIDATE_UPDATEBUF_USAGE); - _SG_VALIDATE(buf->cmn.size >= (int)data->size, VALIDATE_UPDATEBUF_SIZE); - _SG_VALIDATE(buf->cmn.update_frame_index != _sg.frame_index, VALIDATE_UPDATEBUF_ONCE); - _SG_VALIDATE(buf->cmn.append_frame_index != _sg.frame_index, VALIDATE_UPDATEBUF_APPEND); - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_append_buffer(const _sg_buffer_t* buf, const sg_range* data) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(buf); - _SOKOL_UNUSED(data); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT(buf && data && data->ptr); - _sg_validate_begin(); - _SG_VALIDATE(buf->cmn.usage != SG_USAGE_IMMUTABLE, VALIDATE_APPENDBUF_USAGE); - _SG_VALIDATE(buf->cmn.size >= (buf->cmn.append_pos + (int)data->size), VALIDATE_APPENDBUF_SIZE); - _SG_VALIDATE(buf->cmn.update_frame_index != _sg.frame_index, VALIDATE_APPENDBUF_UPDATE); - return _sg_validate_end(); - #endif -} - -_SOKOL_PRIVATE bool _sg_validate_update_image(const _sg_image_t* img, const sg_image_data* data) { - #if !defined(SOKOL_DEBUG) - _SOKOL_UNUSED(img); - _SOKOL_UNUSED(data); - return true; - #else - if (_sg.desc.disable_validation) { - return true; - } - SOKOL_ASSERT(img && data); - _sg_validate_begin(); - _SG_VALIDATE(img->cmn.usage != SG_USAGE_IMMUTABLE, VALIDATE_UPDIMG_USAGE); - _SG_VALIDATE(img->cmn.upd_frame_index != _sg.frame_index, VALIDATE_UPDIMG_ONCE); - _sg_validate_image_data(data, - img->cmn.pixel_format, - img->cmn.width, - img->cmn.height, - (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6 : 1, - img->cmn.num_mipmaps, - img->cmn.num_slices); - return _sg_validate_end(); - #endif -} - -// ██████ ███████ ███████ ██████ ██ ██ ██████ ██████ ███████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ █████ ███████ ██ ██ ██ ██ ██████ ██ █████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ███████ ██████ ██████ ██ ██ ██████ ███████ ███████ -// -// >>resources -_SOKOL_PRIVATE sg_buffer_desc _sg_buffer_desc_defaults(const sg_buffer_desc* desc) { - sg_buffer_desc def = *desc; - def.type = _sg_def(def.type, SG_BUFFERTYPE_VERTEXBUFFER); - def.usage = _sg_def(def.usage, SG_USAGE_IMMUTABLE); - if (def.size == 0) { - def.size = def.data.size; - } else if (def.data.size == 0) { - def.data.size = def.size; - } - return def; -} - -_SOKOL_PRIVATE sg_image_desc _sg_image_desc_defaults(const sg_image_desc* desc) { - sg_image_desc def = *desc; - def.type = _sg_def(def.type, SG_IMAGETYPE_2D); - def.num_slices = _sg_def(def.num_slices, 1); - def.num_mipmaps = _sg_def(def.num_mipmaps, 1); - def.usage = _sg_def(def.usage, SG_USAGE_IMMUTABLE); - if (desc->render_target) { - def.pixel_format = _sg_def(def.pixel_format, _sg.desc.environment.defaults.color_format); - def.sample_count = _sg_def(def.sample_count, _sg.desc.environment.defaults.sample_count); - } else { - def.pixel_format = _sg_def(def.pixel_format, SG_PIXELFORMAT_RGBA8); - def.sample_count = _sg_def(def.sample_count, 1); - } - return def; -} - -_SOKOL_PRIVATE sg_sampler_desc _sg_sampler_desc_defaults(const sg_sampler_desc* desc) { - sg_sampler_desc def = *desc; - def.min_filter = _sg_def(def.min_filter, SG_FILTER_NEAREST); - def.mag_filter = _sg_def(def.mag_filter, SG_FILTER_NEAREST); - def.mipmap_filter = _sg_def(def.mipmap_filter, SG_FILTER_NEAREST); - def.wrap_u = _sg_def(def.wrap_u, SG_WRAP_REPEAT); - def.wrap_v = _sg_def(def.wrap_v, SG_WRAP_REPEAT); - def.wrap_w = _sg_def(def.wrap_w, SG_WRAP_REPEAT); - def.max_lod = _sg_def_flt(def.max_lod, FLT_MAX); - def.border_color = _sg_def(def.border_color, SG_BORDERCOLOR_OPAQUE_BLACK); - def.compare = _sg_def(def.compare, SG_COMPAREFUNC_NEVER); - def.max_anisotropy = _sg_def(def.max_anisotropy, 1); - return def; -} - -_SOKOL_PRIVATE sg_shader_desc _sg_shader_desc_defaults(const sg_shader_desc* desc) { - sg_shader_desc def = *desc; - #if defined(SOKOL_METAL) - def.vs.entry = _sg_def(def.vs.entry, "_main"); - def.fs.entry = _sg_def(def.fs.entry, "_main"); - #else - def.vs.entry = _sg_def(def.vs.entry, "main"); - def.fs.entry = _sg_def(def.fs.entry, "main"); - #endif - #if defined(SOKOL_D3D11) - if (def.vs.source) { - def.vs.d3d11_target = _sg_def(def.vs.d3d11_target, "vs_4_0"); - } - if (def.fs.source) { - def.fs.d3d11_target = _sg_def(def.fs.d3d11_target, "ps_4_0"); - } - #endif - for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { - sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS)? &def.vs : &def.fs; - for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { - sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index]; - if (0 == ub_desc->size) { - break; - } - ub_desc->layout = _sg_def(ub_desc->layout, SG_UNIFORMLAYOUT_NATIVE); - for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) { - sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index]; - if (u_desc->type == SG_UNIFORMTYPE_INVALID) { - break; - } - u_desc->array_count = _sg_def(u_desc->array_count, 1); - } - } - for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { - sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; - if (!img_desc->used) { - break; - } - img_desc->image_type = _sg_def(img_desc->image_type, SG_IMAGETYPE_2D); - img_desc->sample_type = _sg_def(img_desc->sample_type, SG_IMAGESAMPLETYPE_FLOAT); - } - for (int smp_index = 0; smp_index < SG_MAX_SHADERSTAGE_SAMPLERS; smp_index++) { - sg_shader_sampler_desc* smp_desc = &stage_desc->samplers[smp_index]; - if (!smp_desc->used) { - break; - } - smp_desc->sampler_type = _sg_def(smp_desc->sampler_type, SG_SAMPLERTYPE_FILTERING); - } - } - return def; -} - -_SOKOL_PRIVATE sg_pipeline_desc _sg_pipeline_desc_defaults(const sg_pipeline_desc* desc) { - sg_pipeline_desc def = *desc; - - def.primitive_type = _sg_def(def.primitive_type, SG_PRIMITIVETYPE_TRIANGLES); - def.index_type = _sg_def(def.index_type, SG_INDEXTYPE_NONE); - def.cull_mode = _sg_def(def.cull_mode, SG_CULLMODE_NONE); - def.face_winding = _sg_def(def.face_winding, SG_FACEWINDING_CW); - def.sample_count = _sg_def(def.sample_count, _sg.desc.environment.defaults.sample_count); - - def.stencil.front.compare = _sg_def(def.stencil.front.compare, SG_COMPAREFUNC_ALWAYS); - def.stencil.front.fail_op = _sg_def(def.stencil.front.fail_op, SG_STENCILOP_KEEP); - def.stencil.front.depth_fail_op = _sg_def(def.stencil.front.depth_fail_op, SG_STENCILOP_KEEP); - def.stencil.front.pass_op = _sg_def(def.stencil.front.pass_op, SG_STENCILOP_KEEP); - def.stencil.back.compare = _sg_def(def.stencil.back.compare, SG_COMPAREFUNC_ALWAYS); - def.stencil.back.fail_op = _sg_def(def.stencil.back.fail_op, SG_STENCILOP_KEEP); - def.stencil.back.depth_fail_op = _sg_def(def.stencil.back.depth_fail_op, SG_STENCILOP_KEEP); - def.stencil.back.pass_op = _sg_def(def.stencil.back.pass_op, SG_STENCILOP_KEEP); - - def.depth.compare = _sg_def(def.depth.compare, SG_COMPAREFUNC_ALWAYS); - def.depth.pixel_format = _sg_def(def.depth.pixel_format, _sg.desc.environment.defaults.depth_format); - if (def.colors[0].pixel_format == SG_PIXELFORMAT_NONE) { - // special case depth-only rendering, enforce a color count of 0 - def.color_count = 0; - } else { - def.color_count = _sg_def(def.color_count, 1); - } - if (def.color_count > SG_MAX_COLOR_ATTACHMENTS) { - def.color_count = SG_MAX_COLOR_ATTACHMENTS; - } - for (int i = 0; i < def.color_count; i++) { - sg_color_target_state* cs = &def.colors[i]; - cs->pixel_format = _sg_def(cs->pixel_format, _sg.desc.environment.defaults.color_format); - cs->write_mask = _sg_def(cs->write_mask, SG_COLORMASK_RGBA); - sg_blend_state* bs = &def.colors[i].blend; - bs->src_factor_rgb = _sg_def(bs->src_factor_rgb, SG_BLENDFACTOR_ONE); - bs->dst_factor_rgb = _sg_def(bs->dst_factor_rgb, SG_BLENDFACTOR_ZERO); - bs->op_rgb = _sg_def(bs->op_rgb, SG_BLENDOP_ADD); - bs->src_factor_alpha = _sg_def(bs->src_factor_alpha, SG_BLENDFACTOR_ONE); - bs->dst_factor_alpha = _sg_def(bs->dst_factor_alpha, SG_BLENDFACTOR_ZERO); - bs->op_alpha = _sg_def(bs->op_alpha, SG_BLENDOP_ADD); - } - - for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { - sg_vertex_attr_state* a_state = &def.layout.attrs[attr_index]; - if (a_state->format == SG_VERTEXFORMAT_INVALID) { - break; - } - SOKOL_ASSERT(a_state->buffer_index < SG_MAX_VERTEX_BUFFERS); - sg_vertex_buffer_layout_state* l_state = &def.layout.buffers[a_state->buffer_index]; - l_state->step_func = _sg_def(l_state->step_func, SG_VERTEXSTEP_PER_VERTEX); - l_state->step_rate = _sg_def(l_state->step_rate, 1); - } - - // resolve vertex layout strides and offsets - int auto_offset[SG_MAX_VERTEX_BUFFERS]; - _sg_clear(auto_offset, sizeof(auto_offset)); - bool use_auto_offset = true; - for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { - // to use computed offsets, *all* attr offsets must be 0 - if (def.layout.attrs[attr_index].offset != 0) { - use_auto_offset = false; - } - } - for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { - sg_vertex_attr_state* a_state = &def.layout.attrs[attr_index]; - if (a_state->format == SG_VERTEXFORMAT_INVALID) { - break; - } - SOKOL_ASSERT(a_state->buffer_index < SG_MAX_VERTEX_BUFFERS); - if (use_auto_offset) { - a_state->offset = auto_offset[a_state->buffer_index]; - } - auto_offset[a_state->buffer_index] += _sg_vertexformat_bytesize(a_state->format); - } - // compute vertex strides if needed - for (int buf_index = 0; buf_index < SG_MAX_VERTEX_BUFFERS; buf_index++) { - sg_vertex_buffer_layout_state* l_state = &def.layout.buffers[buf_index]; - if (l_state->stride == 0) { - l_state->stride = auto_offset[buf_index]; - } - } - - return def; -} - -_SOKOL_PRIVATE sg_attachments_desc _sg_attachments_desc_defaults(const sg_attachments_desc* desc) { - sg_attachments_desc def = *desc; - return def; -} - -_SOKOL_PRIVATE sg_buffer _sg_alloc_buffer(void) { - sg_buffer res; - int slot_index = _sg_pool_alloc_index(&_sg.pools.buffer_pool); - if (_SG_INVALID_SLOT_INDEX != slot_index) { - res.id = _sg_slot_alloc(&_sg.pools.buffer_pool, &_sg.pools.buffers[slot_index].slot, slot_index); - } else { - res.id = SG_INVALID_ID; - _SG_ERROR(BUFFER_POOL_EXHAUSTED); - } - return res; -} - -_SOKOL_PRIVATE sg_image _sg_alloc_image(void) { - sg_image res; - int slot_index = _sg_pool_alloc_index(&_sg.pools.image_pool); - if (_SG_INVALID_SLOT_INDEX != slot_index) { - res.id = _sg_slot_alloc(&_sg.pools.image_pool, &_sg.pools.images[slot_index].slot, slot_index); - } else { - res.id = SG_INVALID_ID; - _SG_ERROR(IMAGE_POOL_EXHAUSTED); - } - return res; -} - -_SOKOL_PRIVATE sg_sampler _sg_alloc_sampler(void) { - sg_sampler res; - int slot_index = _sg_pool_alloc_index(&_sg.pools.sampler_pool); - if (_SG_INVALID_SLOT_INDEX != slot_index) { - res.id = _sg_slot_alloc(&_sg.pools.sampler_pool, &_sg.pools.samplers[slot_index].slot, slot_index); - } else { - res.id = SG_INVALID_ID; - _SG_ERROR(SAMPLER_POOL_EXHAUSTED); - } - return res; -} - -_SOKOL_PRIVATE sg_shader _sg_alloc_shader(void) { - sg_shader res; - int slot_index = _sg_pool_alloc_index(&_sg.pools.shader_pool); - if (_SG_INVALID_SLOT_INDEX != slot_index) { - res.id = _sg_slot_alloc(&_sg.pools.shader_pool, &_sg.pools.shaders[slot_index].slot, slot_index); - } else { - res.id = SG_INVALID_ID; - _SG_ERROR(SHADER_POOL_EXHAUSTED); - } - return res; -} - -_SOKOL_PRIVATE sg_pipeline _sg_alloc_pipeline(void) { - sg_pipeline res; - int slot_index = _sg_pool_alloc_index(&_sg.pools.pipeline_pool); - if (_SG_INVALID_SLOT_INDEX != slot_index) { - res.id =_sg_slot_alloc(&_sg.pools.pipeline_pool, &_sg.pools.pipelines[slot_index].slot, slot_index); - } else { - res.id = SG_INVALID_ID; - _SG_ERROR(PIPELINE_POOL_EXHAUSTED); - } - return res; -} - -_SOKOL_PRIVATE sg_attachments _sg_alloc_attachments(void) { - sg_attachments res; - int slot_index = _sg_pool_alloc_index(&_sg.pools.attachments_pool); - if (_SG_INVALID_SLOT_INDEX != slot_index) { - res.id = _sg_slot_alloc(&_sg.pools.attachments_pool, &_sg.pools.attachments[slot_index].slot, slot_index); - } else { - res.id = SG_INVALID_ID; - _SG_ERROR(PASS_POOL_EXHAUSTED); - } - return res; -} - -_SOKOL_PRIVATE void _sg_dealloc_buffer(_sg_buffer_t* buf) { - SOKOL_ASSERT(buf && (buf->slot.state == SG_RESOURCESTATE_ALLOC) && (buf->slot.id != SG_INVALID_ID)); - _sg_pool_free_index(&_sg.pools.buffer_pool, _sg_slot_index(buf->slot.id)); - _sg_reset_slot(&buf->slot); -} - -_SOKOL_PRIVATE void _sg_dealloc_image(_sg_image_t* img) { - SOKOL_ASSERT(img && (img->slot.state == SG_RESOURCESTATE_ALLOC) && (img->slot.id != SG_INVALID_ID)); - _sg_pool_free_index(&_sg.pools.image_pool, _sg_slot_index(img->slot.id)); - _sg_reset_slot(&img->slot); -} - -_SOKOL_PRIVATE void _sg_dealloc_sampler(_sg_sampler_t* smp) { - SOKOL_ASSERT(smp && (smp->slot.state == SG_RESOURCESTATE_ALLOC) && (smp->slot.id != SG_INVALID_ID)); - _sg_pool_free_index(&_sg.pools.sampler_pool, _sg_slot_index(smp->slot.id)); - _sg_reset_slot(&smp->slot); -} - -_SOKOL_PRIVATE void _sg_dealloc_shader(_sg_shader_t* shd) { - SOKOL_ASSERT(shd && (shd->slot.state == SG_RESOURCESTATE_ALLOC) && (shd->slot.id != SG_INVALID_ID)); - _sg_pool_free_index(&_sg.pools.shader_pool, _sg_slot_index(shd->slot.id)); - _sg_reset_slot(&shd->slot); -} - -_SOKOL_PRIVATE void _sg_dealloc_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip && (pip->slot.state == SG_RESOURCESTATE_ALLOC) && (pip->slot.id != SG_INVALID_ID)); - _sg_pool_free_index(&_sg.pools.pipeline_pool, _sg_slot_index(pip->slot.id)); - _sg_reset_slot(&pip->slot); -} - -_SOKOL_PRIVATE void _sg_dealloc_attachments(_sg_attachments_t* atts) { - SOKOL_ASSERT(atts && (atts->slot.state == SG_RESOURCESTATE_ALLOC) && (atts->slot.id != SG_INVALID_ID)); - _sg_pool_free_index(&_sg.pools.attachments_pool, _sg_slot_index(atts->slot.id)); - _sg_reset_slot(&atts->slot); -} - -_SOKOL_PRIVATE void _sg_init_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { - SOKOL_ASSERT(buf && (buf->slot.state == SG_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - if (_sg_validate_buffer_desc(desc)) { - _sg_buffer_common_init(&buf->cmn, desc); - buf->slot.state = _sg_create_buffer(buf, desc); - } else { - buf->slot.state = SG_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT((buf->slot.state == SG_RESOURCESTATE_VALID)||(buf->slot.state == SG_RESOURCESTATE_FAILED)); -} - -_SOKOL_PRIVATE void _sg_init_image(_sg_image_t* img, const sg_image_desc* desc) { - SOKOL_ASSERT(img && (img->slot.state == SG_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - if (_sg_validate_image_desc(desc)) { - _sg_image_common_init(&img->cmn, desc); - img->slot.state = _sg_create_image(img, desc); - } else { - img->slot.state = SG_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT((img->slot.state == SG_RESOURCESTATE_VALID)||(img->slot.state == SG_RESOURCESTATE_FAILED)); -} - -_SOKOL_PRIVATE void _sg_init_sampler(_sg_sampler_t* smp, const sg_sampler_desc* desc) { - SOKOL_ASSERT(smp && (smp->slot.state == SG_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - if (_sg_validate_sampler_desc(desc)) { - _sg_sampler_common_init(&smp->cmn, desc); - smp->slot.state = _sg_create_sampler(smp, desc); - } else { - smp->slot.state = SG_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT((smp->slot.state == SG_RESOURCESTATE_VALID)||(smp->slot.state == SG_RESOURCESTATE_FAILED)); -} - -_SOKOL_PRIVATE void _sg_init_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { - SOKOL_ASSERT(shd && (shd->slot.state == SG_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - if (_sg_validate_shader_desc(desc)) { - _sg_shader_common_init(&shd->cmn, desc); - shd->slot.state = _sg_create_shader(shd, desc); - } else { - shd->slot.state = SG_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT((shd->slot.state == SG_RESOURCESTATE_VALID)||(shd->slot.state == SG_RESOURCESTATE_FAILED)); -} - -_SOKOL_PRIVATE void _sg_init_pipeline(_sg_pipeline_t* pip, const sg_pipeline_desc* desc) { - SOKOL_ASSERT(pip && (pip->slot.state == SG_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - if (_sg_validate_pipeline_desc(desc)) { - _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, desc->shader.id); - if (shd && (shd->slot.state == SG_RESOURCESTATE_VALID)) { - _sg_pipeline_common_init(&pip->cmn, desc); - pip->slot.state = _sg_create_pipeline(pip, shd, desc); - } else { - pip->slot.state = SG_RESOURCESTATE_FAILED; - } - } else { - pip->slot.state = SG_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT((pip->slot.state == SG_RESOURCESTATE_VALID)||(pip->slot.state == SG_RESOURCESTATE_FAILED)); -} - -_SOKOL_PRIVATE void _sg_init_attachments(_sg_attachments_t* atts, const sg_attachments_desc* desc) { - SOKOL_ASSERT(atts && atts->slot.state == SG_RESOURCESTATE_ALLOC); - SOKOL_ASSERT(desc); - if (_sg_validate_attachments_desc(desc)) { - // lookup pass attachment image pointers - _sg_image_t* color_images[SG_MAX_COLOR_ATTACHMENTS] = { 0 }; - _sg_image_t* resolve_images[SG_MAX_COLOR_ATTACHMENTS] = { 0 }; - _sg_image_t* ds_image = 0; - // NOTE: validation already checked that all surfaces are same width/height - int width = 0; - int height = 0; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (desc->colors[i].image.id) { - color_images[i] = _sg_lookup_image(&_sg.pools, desc->colors[i].image.id); - if (!(color_images[i] && color_images[i]->slot.state == SG_RESOURCESTATE_VALID)) { - atts->slot.state = SG_RESOURCESTATE_FAILED; - return; - } - const int mip_level = desc->colors[i].mip_level; - width = _sg_miplevel_dim(color_images[i]->cmn.width, mip_level); - height = _sg_miplevel_dim(color_images[i]->cmn.height, mip_level); - } - if (desc->resolves[i].image.id) { - resolve_images[i] = _sg_lookup_image(&_sg.pools, desc->resolves[i].image.id); - if (!(resolve_images[i] && resolve_images[i]->slot.state == SG_RESOURCESTATE_VALID)) { - atts->slot.state = SG_RESOURCESTATE_FAILED; - return; - } - } - } - if (desc->depth_stencil.image.id) { - ds_image = _sg_lookup_image(&_sg.pools, desc->depth_stencil.image.id); - if (!(ds_image && ds_image->slot.state == SG_RESOURCESTATE_VALID)) { - atts->slot.state = SG_RESOURCESTATE_FAILED; - return; - } - const int mip_level = desc->depth_stencil.mip_level; - width = _sg_miplevel_dim(ds_image->cmn.width, mip_level); - height = _sg_miplevel_dim(ds_image->cmn.height, mip_level); - } - _sg_attachments_common_init(&atts->cmn, desc, width, height); - atts->slot.state = _sg_create_attachments(atts, color_images, resolve_images, ds_image, desc); - } else { - atts->slot.state = SG_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT((atts->slot.state == SG_RESOURCESTATE_VALID)||(atts->slot.state == SG_RESOURCESTATE_FAILED)); -} - -_SOKOL_PRIVATE void _sg_uninit_buffer(_sg_buffer_t* buf) { - SOKOL_ASSERT(buf && ((buf->slot.state == SG_RESOURCESTATE_VALID) || (buf->slot.state == SG_RESOURCESTATE_FAILED))); - _sg_discard_buffer(buf); - _sg_reset_buffer_to_alloc_state(buf); -} - -_SOKOL_PRIVATE void _sg_uninit_image(_sg_image_t* img) { - SOKOL_ASSERT(img && ((img->slot.state == SG_RESOURCESTATE_VALID) || (img->slot.state == SG_RESOURCESTATE_FAILED))); - _sg_discard_image(img); - _sg_reset_image_to_alloc_state(img); -} - -_SOKOL_PRIVATE void _sg_uninit_sampler(_sg_sampler_t* smp) { - SOKOL_ASSERT(smp && ((smp->slot.state == SG_RESOURCESTATE_VALID) || (smp->slot.state == SG_RESOURCESTATE_FAILED))); - _sg_discard_sampler(smp); - _sg_reset_sampler_to_alloc_state(smp); -} - -_SOKOL_PRIVATE void _sg_uninit_shader(_sg_shader_t* shd) { - SOKOL_ASSERT(shd && ((shd->slot.state == SG_RESOURCESTATE_VALID) || (shd->slot.state == SG_RESOURCESTATE_FAILED))); - _sg_discard_shader(shd); - _sg_reset_shader_to_alloc_state(shd); -} - -_SOKOL_PRIVATE void _sg_uninit_pipeline(_sg_pipeline_t* pip) { - SOKOL_ASSERT(pip && ((pip->slot.state == SG_RESOURCESTATE_VALID) || (pip->slot.state == SG_RESOURCESTATE_FAILED))); - _sg_discard_pipeline(pip); - _sg_reset_pipeline_to_alloc_state(pip); -} - -_SOKOL_PRIVATE void _sg_uninit_attachments(_sg_attachments_t* atts) { - SOKOL_ASSERT(atts && ((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED))); - _sg_discard_attachments(atts); - _sg_reset_attachments_to_alloc_state(atts); -} - -_SOKOL_PRIVATE void _sg_setup_commit_listeners(const sg_desc* desc) { - SOKOL_ASSERT(desc->max_commit_listeners > 0); - SOKOL_ASSERT(0 == _sg.commit_listeners.items); - SOKOL_ASSERT(0 == _sg.commit_listeners.num); - SOKOL_ASSERT(0 == _sg.commit_listeners.upper); - _sg.commit_listeners.num = desc->max_commit_listeners; - const size_t size = (size_t)_sg.commit_listeners.num * sizeof(sg_commit_listener); - _sg.commit_listeners.items = (sg_commit_listener*)_sg_malloc_clear(size); -} - -_SOKOL_PRIVATE void _sg_discard_commit_listeners(void) { - SOKOL_ASSERT(0 != _sg.commit_listeners.items); - _sg_free(_sg.commit_listeners.items); - _sg.commit_listeners.items = 0; -} - -_SOKOL_PRIVATE void _sg_notify_commit_listeners(void) { - SOKOL_ASSERT(_sg.commit_listeners.items); - for (int i = 0; i < _sg.commit_listeners.upper; i++) { - const sg_commit_listener* listener = &_sg.commit_listeners.items[i]; - if (listener->func) { - listener->func(listener->user_data); - } - } -} - -_SOKOL_PRIVATE bool _sg_add_commit_listener(const sg_commit_listener* new_listener) { - SOKOL_ASSERT(new_listener && new_listener->func); - SOKOL_ASSERT(_sg.commit_listeners.items); - // first check if the listener hadn't been added already - for (int i = 0; i < _sg.commit_listeners.upper; i++) { - const sg_commit_listener* slot = &_sg.commit_listeners.items[i]; - if ((slot->func == new_listener->func) && (slot->user_data == new_listener->user_data)) { - _SG_ERROR(IDENTICAL_COMMIT_LISTENER); - return false; - } - } - // first try to plug a hole - sg_commit_listener* slot = 0; - for (int i = 0; i < _sg.commit_listeners.upper; i++) { - if (_sg.commit_listeners.items[i].func == 0) { - slot = &_sg.commit_listeners.items[i]; - break; - } - } - if (!slot) { - // append to end - if (_sg.commit_listeners.upper < _sg.commit_listeners.num) { - slot = &_sg.commit_listeners.items[_sg.commit_listeners.upper++]; - } - } - if (!slot) { - _SG_ERROR(COMMIT_LISTENER_ARRAY_FULL); - return false; - } - *slot = *new_listener; - return true; -} - -_SOKOL_PRIVATE bool _sg_remove_commit_listener(const sg_commit_listener* listener) { - SOKOL_ASSERT(listener && listener->func); - SOKOL_ASSERT(_sg.commit_listeners.items); - for (int i = 0; i < _sg.commit_listeners.upper; i++) { - sg_commit_listener* slot = &_sg.commit_listeners.items[i]; - // both the function pointer and user data must match! - if ((slot->func == listener->func) && (slot->user_data == listener->user_data)) { - slot->func = 0; - slot->user_data = 0; - // NOTE: since _sg_add_commit_listener() already catches duplicates, - // we don't need to worry about them here - return true; - } - } - return false; -} - -_SOKOL_PRIVATE sg_desc _sg_desc_defaults(const sg_desc* desc) { - /* - NOTE: on WebGPU, the default color pixel format MUST be provided, - cannot be a default compile-time constant. - */ - sg_desc res = *desc; - #if defined(SOKOL_WGPU) - SOKOL_ASSERT(SG_PIXELFORMAT_NONE < res.environment.defaults.color_format); - #elif defined(SOKOL_METAL) || defined(SOKOL_D3D11) - res.environment.defaults.color_format = _sg_def(res.environment.defaults.color_format, SG_PIXELFORMAT_BGRA8); - #else - res.environment.defaults.color_format = _sg_def(res.environment.defaults.color_format, SG_PIXELFORMAT_RGBA8); - #endif - res.environment.defaults.depth_format = _sg_def(res.environment.defaults.depth_format, SG_PIXELFORMAT_DEPTH_STENCIL); - res.environment.defaults.sample_count = _sg_def(res.environment.defaults.sample_count, 1); - res.buffer_pool_size = _sg_def(res.buffer_pool_size, _SG_DEFAULT_BUFFER_POOL_SIZE); - res.image_pool_size = _sg_def(res.image_pool_size, _SG_DEFAULT_IMAGE_POOL_SIZE); - res.sampler_pool_size = _sg_def(res.sampler_pool_size, _SG_DEFAULT_SAMPLER_POOL_SIZE); - res.shader_pool_size = _sg_def(res.shader_pool_size, _SG_DEFAULT_SHADER_POOL_SIZE); - res.pipeline_pool_size = _sg_def(res.pipeline_pool_size, _SG_DEFAULT_PIPELINE_POOL_SIZE); - res.attachments_pool_size = _sg_def(res.attachments_pool_size, _SG_DEFAULT_ATTACHMENTS_POOL_SIZE); - res.uniform_buffer_size = _sg_def(res.uniform_buffer_size, _SG_DEFAULT_UB_SIZE); - res.max_commit_listeners = _sg_def(res.max_commit_listeners, _SG_DEFAULT_MAX_COMMIT_LISTENERS); - res.wgpu_bindgroups_cache_size = _sg_def(res.wgpu_bindgroups_cache_size, _SG_DEFAULT_WGPU_BINDGROUP_CACHE_SIZE); - return res; -} - -_SOKOL_PRIVATE sg_pass _sg_pass_defaults(const sg_pass* pass) { - sg_pass res = *pass; - if (res.attachments.id == SG_INVALID_ID) { - // this is a swapchain-pass - res.swapchain.sample_count = _sg_def(res.swapchain.sample_count, _sg.desc.environment.defaults.sample_count); - res.swapchain.color_format = _sg_def(res.swapchain.color_format, _sg.desc.environment.defaults.color_format); - res.swapchain.depth_format = _sg_def(res.swapchain.depth_format, _sg.desc.environment.defaults.depth_format); - } - res.action = _sg_pass_action_defaults(&res.action); - return res; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void sg_setup(const sg_desc* desc) { - SOKOL_ASSERT(desc); - SOKOL_ASSERT((desc->_start_canary == 0) && (desc->_end_canary == 0)); - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - _SG_CLEAR_ARC_STRUCT(_sg_state_t, _sg); - _sg.desc = _sg_desc_defaults(desc); - _sg_setup_pools(&_sg.pools, &_sg.desc); - _sg_setup_commit_listeners(&_sg.desc); - _sg.frame_index = 1; - _sg.stats_enabled = true; - _sg_setup_backend(&_sg.desc); - _sg.valid = true; -} - -SOKOL_API_IMPL void sg_shutdown(void) { - _sg_discard_all_resources(&_sg.pools); - _sg_discard_backend(); - _sg_discard_commit_listeners(); - _sg_discard_pools(&_sg.pools); - _SG_CLEAR_ARC_STRUCT(_sg_state_t, _sg); -} - -SOKOL_API_IMPL bool sg_isvalid(void) { - return _sg.valid; -} - -SOKOL_API_IMPL sg_desc sg_query_desc(void) { - SOKOL_ASSERT(_sg.valid); - return _sg.desc; -} - -SOKOL_API_IMPL sg_backend sg_query_backend(void) { - SOKOL_ASSERT(_sg.valid); - return _sg.backend; -} - -SOKOL_API_IMPL sg_features sg_query_features(void) { - SOKOL_ASSERT(_sg.valid); - return _sg.features; -} - -SOKOL_API_IMPL sg_limits sg_query_limits(void) { - SOKOL_ASSERT(_sg.valid); - return _sg.limits; -} - -SOKOL_API_IMPL sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt) { - SOKOL_ASSERT(_sg.valid); - int fmt_index = (int) fmt; - SOKOL_ASSERT((fmt_index > SG_PIXELFORMAT_NONE) && (fmt_index < _SG_PIXELFORMAT_NUM)); - const _sg_pixelformat_info_t* src = &_sg.formats[fmt_index]; - sg_pixelformat_info res; - _sg_clear(&res, sizeof(res)); - res.sample = src->sample; - res.filter = src->filter; - res.render = src->render; - res.blend = src->blend; - res.msaa = src->msaa; - res.depth = src->depth; - res.compressed = _sg_is_compressed_pixel_format(fmt); - if (!res.compressed) { - res.bytes_per_pixel = _sg_pixelformat_bytesize(fmt); - } - return res; -} - -SOKOL_API_IMPL int sg_query_row_pitch(sg_pixel_format fmt, int width, int row_align_bytes) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(width > 0); - SOKOL_ASSERT((row_align_bytes > 0) && _sg_ispow2(row_align_bytes)); - SOKOL_ASSERT(((int)fmt > SG_PIXELFORMAT_NONE) && ((int)fmt < _SG_PIXELFORMAT_NUM)); - return _sg_row_pitch(fmt, width, row_align_bytes); -} - -SOKOL_API_IMPL int sg_query_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align_bytes) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT((width > 0) && (height > 0)); - SOKOL_ASSERT((row_align_bytes > 0) && _sg_ispow2(row_align_bytes)); - SOKOL_ASSERT(((int)fmt > SG_PIXELFORMAT_NONE) && ((int)fmt < _SG_PIXELFORMAT_NUM)); - return _sg_surface_pitch(fmt, width, height, row_align_bytes); -} - -SOKOL_API_IMPL sg_frame_stats sg_query_frame_stats(void) { - SOKOL_ASSERT(_sg.valid); - return _sg.prev_stats; -} - -SOKOL_API_IMPL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace_hooks) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(trace_hooks); - _SOKOL_UNUSED(trace_hooks); - #if defined(SOKOL_TRACE_HOOKS) - sg_trace_hooks old_hooks = _sg.hooks; - _sg.hooks = *trace_hooks; - #else - static sg_trace_hooks old_hooks; - _SG_WARN(TRACE_HOOKS_NOT_ENABLED); - #endif - return old_hooks; -} - -SOKOL_API_IMPL sg_buffer sg_alloc_buffer(void) { - SOKOL_ASSERT(_sg.valid); - sg_buffer res = _sg_alloc_buffer(); - _SG_TRACE_ARGS(alloc_buffer, res); - return res; -} - -SOKOL_API_IMPL sg_image sg_alloc_image(void) { - SOKOL_ASSERT(_sg.valid); - sg_image res = _sg_alloc_image(); - _SG_TRACE_ARGS(alloc_image, res); - return res; -} - -SOKOL_API_IMPL sg_sampler sg_alloc_sampler(void) { - SOKOL_ASSERT(_sg.valid); - sg_sampler res = _sg_alloc_sampler(); - _SG_TRACE_ARGS(alloc_sampler, res); - return res; -} - -SOKOL_API_IMPL sg_shader sg_alloc_shader(void) { - SOKOL_ASSERT(_sg.valid); - sg_shader res = _sg_alloc_shader(); - _SG_TRACE_ARGS(alloc_shader, res); - return res; -} - -SOKOL_API_IMPL sg_pipeline sg_alloc_pipeline(void) { - SOKOL_ASSERT(_sg.valid); - sg_pipeline res = _sg_alloc_pipeline(); - _SG_TRACE_ARGS(alloc_pipeline, res); - return res; -} - -SOKOL_API_IMPL sg_attachments sg_alloc_attachments(void) { - SOKOL_ASSERT(_sg.valid); - sg_attachments res = _sg_alloc_attachments(); - _SG_TRACE_ARGS(alloc_attachments, res); - return res; -} - -SOKOL_API_IMPL void sg_dealloc_buffer(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - if (buf->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_buffer(buf); - } else { - _SG_ERROR(DEALLOC_BUFFER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(dealloc_buffer, buf_id); -} - -SOKOL_API_IMPL void sg_dealloc_image(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - if (img->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_image(img); - } else { - _SG_ERROR(DEALLOC_IMAGE_INVALID_STATE); - } - } - _SG_TRACE_ARGS(dealloc_image, img_id); -} - -SOKOL_API_IMPL void sg_dealloc_sampler(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - if (smp->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_sampler(smp); - } else { - _SG_ERROR(DEALLOC_SAMPLER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(dealloc_sampler, smp_id); -} - -SOKOL_API_IMPL void sg_dealloc_shader(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - if (shd->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_shader(shd); - } else { - _SG_ERROR(DEALLOC_SHADER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(dealloc_shader, shd_id); -} - -SOKOL_API_IMPL void sg_dealloc_pipeline(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - if (pip->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_pipeline(pip); - } else { - _SG_ERROR(DEALLOC_PIPELINE_INVALID_STATE); - } - } - _SG_TRACE_ARGS(dealloc_pipeline, pip_id); -} - -SOKOL_API_IMPL void sg_dealloc_attachments(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - if (atts->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_attachments(atts); - } else { - _SG_ERROR(DEALLOC_ATTACHMENTS_INVALID_STATE); - } - } - _SG_TRACE_ARGS(dealloc_attachments, atts_id); -} - -SOKOL_API_IMPL void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc) { - SOKOL_ASSERT(_sg.valid); - sg_buffer_desc desc_def = _sg_buffer_desc_defaults(desc); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - if (buf->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_init_buffer(buf, &desc_def); - SOKOL_ASSERT((buf->slot.state == SG_RESOURCESTATE_VALID) || (buf->slot.state == SG_RESOURCESTATE_FAILED)); - } else { - _SG_ERROR(INIT_BUFFER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(init_buffer, buf_id, &desc_def); -} - -SOKOL_API_IMPL void sg_init_image(sg_image img_id, const sg_image_desc* desc) { - SOKOL_ASSERT(_sg.valid); - sg_image_desc desc_def = _sg_image_desc_defaults(desc); - _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - if (img->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_init_image(img, &desc_def); - SOKOL_ASSERT((img->slot.state == SG_RESOURCESTATE_VALID) || (img->slot.state == SG_RESOURCESTATE_FAILED)); - } else { - _SG_ERROR(INIT_IMAGE_INVALID_STATE); - } - } - _SG_TRACE_ARGS(init_image, img_id, &desc_def); -} - -SOKOL_API_IMPL void sg_init_sampler(sg_sampler smp_id, const sg_sampler_desc* desc) { - SOKOL_ASSERT(_sg.valid); - sg_sampler_desc desc_def = _sg_sampler_desc_defaults(desc); - _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - if (smp->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_init_sampler(smp, &desc_def); - SOKOL_ASSERT((smp->slot.state == SG_RESOURCESTATE_VALID) || (smp->slot.state == SG_RESOURCESTATE_FAILED)); - } else { - _SG_ERROR(INIT_SAMPLER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(init_sampler, smp_id, &desc_def); -} - -SOKOL_API_IMPL void sg_init_shader(sg_shader shd_id, const sg_shader_desc* desc) { - SOKOL_ASSERT(_sg.valid); - sg_shader_desc desc_def = _sg_shader_desc_defaults(desc); - _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - if (shd->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_init_shader(shd, &desc_def); - SOKOL_ASSERT((shd->slot.state == SG_RESOURCESTATE_VALID) || (shd->slot.state == SG_RESOURCESTATE_FAILED)); - } else { - _SG_ERROR(INIT_SHADER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(init_shader, shd_id, &desc_def); -} - -SOKOL_API_IMPL void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* desc) { - SOKOL_ASSERT(_sg.valid); - sg_pipeline_desc desc_def = _sg_pipeline_desc_defaults(desc); - _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - if (pip->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_init_pipeline(pip, &desc_def); - SOKOL_ASSERT((pip->slot.state == SG_RESOURCESTATE_VALID) || (pip->slot.state == SG_RESOURCESTATE_FAILED)); - } else { - _SG_ERROR(INIT_PIPELINE_INVALID_STATE); - } - } - _SG_TRACE_ARGS(init_pipeline, pip_id, &desc_def); -} - -SOKOL_API_IMPL void sg_init_attachments(sg_attachments atts_id, const sg_attachments_desc* desc) { - SOKOL_ASSERT(_sg.valid); - sg_attachments_desc desc_def = _sg_attachments_desc_defaults(desc); - _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - if (atts->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_init_attachments(atts, &desc_def); - SOKOL_ASSERT((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED)); - } else { - _SG_ERROR(INIT_ATTACHMENTS_INVALID_STATE); - } - } - _SG_TRACE_ARGS(init_attachments, atts_id, &desc_def); -} - -SOKOL_API_IMPL void sg_uninit_buffer(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - if ((buf->slot.state == SG_RESOURCESTATE_VALID) || (buf->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_buffer(buf); - SOKOL_ASSERT(buf->slot.state == SG_RESOURCESTATE_ALLOC); - } else { - _SG_ERROR(UNINIT_BUFFER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(uninit_buffer, buf_id); -} - -SOKOL_API_IMPL void sg_uninit_image(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - if ((img->slot.state == SG_RESOURCESTATE_VALID) || (img->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_image(img); - SOKOL_ASSERT(img->slot.state == SG_RESOURCESTATE_ALLOC); - } else { - _SG_ERROR(UNINIT_IMAGE_INVALID_STATE); - } - } - _SG_TRACE_ARGS(uninit_image, img_id); -} - -SOKOL_API_IMPL void sg_uninit_sampler(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - if ((smp->slot.state == SG_RESOURCESTATE_VALID) || (smp->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_sampler(smp); - SOKOL_ASSERT(smp->slot.state == SG_RESOURCESTATE_ALLOC); - } else { - _SG_ERROR(UNINIT_SAMPLER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(uninit_sampler, smp_id); -} - -SOKOL_API_IMPL void sg_uninit_shader(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - if ((shd->slot.state == SG_RESOURCESTATE_VALID) || (shd->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_shader(shd); - SOKOL_ASSERT(shd->slot.state == SG_RESOURCESTATE_ALLOC); - } else { - _SG_ERROR(UNINIT_SHADER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(uninit_shader, shd_id); -} - -SOKOL_API_IMPL void sg_uninit_pipeline(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - if ((pip->slot.state == SG_RESOURCESTATE_VALID) || (pip->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_pipeline(pip); - SOKOL_ASSERT(pip->slot.state == SG_RESOURCESTATE_ALLOC); - } else { - _SG_ERROR(UNINIT_PIPELINE_INVALID_STATE); - } - } - _SG_TRACE_ARGS(uninit_pipeline, pip_id); -} - -SOKOL_API_IMPL void sg_uninit_attachments(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - if ((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_attachments(atts); - SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_ALLOC); - } else { - _SG_ERROR(UNINIT_ATTACHMENTS_INVALID_STATE); - } - } - _SG_TRACE_ARGS(uninit_attachments, atts_id); -} - -SOKOL_API_IMPL void sg_fail_buffer(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - if (buf->slot.state == SG_RESOURCESTATE_ALLOC) { - buf->slot.state = SG_RESOURCESTATE_FAILED; - } else { - _SG_ERROR(FAIL_BUFFER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(fail_buffer, buf_id); -} - -SOKOL_API_IMPL void sg_fail_image(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - if (img->slot.state == SG_RESOURCESTATE_ALLOC) { - img->slot.state = SG_RESOURCESTATE_FAILED; - } else { - _SG_ERROR(FAIL_IMAGE_INVALID_STATE); - } - } - _SG_TRACE_ARGS(fail_image, img_id); -} - -SOKOL_API_IMPL void sg_fail_sampler(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - if (smp->slot.state == SG_RESOURCESTATE_ALLOC) { - smp->slot.state = SG_RESOURCESTATE_FAILED; - } else { - _SG_ERROR(FAIL_SAMPLER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(fail_sampler, smp_id); -} - -SOKOL_API_IMPL void sg_fail_shader(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - if (shd->slot.state == SG_RESOURCESTATE_ALLOC) { - shd->slot.state = SG_RESOURCESTATE_FAILED; - } else { - _SG_ERROR(FAIL_SHADER_INVALID_STATE); - } - } - _SG_TRACE_ARGS(fail_shader, shd_id); -} - -SOKOL_API_IMPL void sg_fail_pipeline(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - if (pip->slot.state == SG_RESOURCESTATE_ALLOC) { - pip->slot.state = SG_RESOURCESTATE_FAILED; - } else { - _SG_ERROR(FAIL_PIPELINE_INVALID_STATE); - } - } - _SG_TRACE_ARGS(fail_pipeline, pip_id); -} - -SOKOL_API_IMPL void sg_fail_attachments(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - if (atts->slot.state == SG_RESOURCESTATE_ALLOC) { - atts->slot.state = SG_RESOURCESTATE_FAILED; - } else { - _SG_ERROR(FAIL_ATTACHMENTS_INVALID_STATE); - } - } - _SG_TRACE_ARGS(fail_attachments, atts_id); -} - -SOKOL_API_IMPL sg_resource_state sg_query_buffer_state(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - sg_resource_state res = buf ? buf->slot.state : SG_RESOURCESTATE_INVALID; - return res; -} - -SOKOL_API_IMPL sg_resource_state sg_query_image_state(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - sg_resource_state res = img ? img->slot.state : SG_RESOURCESTATE_INVALID; - return res; -} - -SOKOL_API_IMPL sg_resource_state sg_query_sampler_state(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - sg_resource_state res = smp ? smp->slot.state : SG_RESOURCESTATE_INVALID; - return res; -} - -SOKOL_API_IMPL sg_resource_state sg_query_shader_state(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - sg_resource_state res = shd ? shd->slot.state : SG_RESOURCESTATE_INVALID; - return res; -} - -SOKOL_API_IMPL sg_resource_state sg_query_pipeline_state(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - sg_resource_state res = pip ? pip->slot.state : SG_RESOURCESTATE_INVALID; - return res; -} - -SOKOL_API_IMPL sg_resource_state sg_query_attachments_state(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - sg_resource_state res = atts ? atts->slot.state : SG_RESOURCESTATE_INVALID; - return res; -} - -SOKOL_API_IMPL sg_buffer sg_make_buffer(const sg_buffer_desc* desc) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(desc); - sg_buffer_desc desc_def = _sg_buffer_desc_defaults(desc); - sg_buffer buf_id = _sg_alloc_buffer(); - if (buf_id.id != SG_INVALID_ID) { - _sg_buffer_t* buf = _sg_buffer_at(&_sg.pools, buf_id.id); - SOKOL_ASSERT(buf && (buf->slot.state == SG_RESOURCESTATE_ALLOC)); - _sg_init_buffer(buf, &desc_def); - SOKOL_ASSERT((buf->slot.state == SG_RESOURCESTATE_VALID) || (buf->slot.state == SG_RESOURCESTATE_FAILED)); - } - _SG_TRACE_ARGS(make_buffer, &desc_def, buf_id); - return buf_id; -} - -SOKOL_API_IMPL sg_image sg_make_image(const sg_image_desc* desc) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(desc); - sg_image_desc desc_def = _sg_image_desc_defaults(desc); - sg_image img_id = _sg_alloc_image(); - if (img_id.id != SG_INVALID_ID) { - _sg_image_t* img = _sg_image_at(&_sg.pools, img_id.id); - SOKOL_ASSERT(img && (img->slot.state == SG_RESOURCESTATE_ALLOC)); - _sg_init_image(img, &desc_def); - SOKOL_ASSERT((img->slot.state == SG_RESOURCESTATE_VALID) || (img->slot.state == SG_RESOURCESTATE_FAILED)); - } - _SG_TRACE_ARGS(make_image, &desc_def, img_id); - return img_id; -} - -SOKOL_API_IMPL sg_sampler sg_make_sampler(const sg_sampler_desc* desc) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(desc); - sg_sampler_desc desc_def = _sg_sampler_desc_defaults(desc); - sg_sampler smp_id = _sg_alloc_sampler(); - if (smp_id.id != SG_INVALID_ID) { - _sg_sampler_t* smp = _sg_sampler_at(&_sg.pools, smp_id.id); - SOKOL_ASSERT(smp && (smp->slot.state == SG_RESOURCESTATE_ALLOC)); - _sg_init_sampler(smp, &desc_def); - SOKOL_ASSERT((smp->slot.state == SG_RESOURCESTATE_VALID) || (smp->slot.state == SG_RESOURCESTATE_FAILED)); - } - _SG_TRACE_ARGS(make_sampler, &desc_def, smp_id); - return smp_id; -} - -SOKOL_API_IMPL sg_shader sg_make_shader(const sg_shader_desc* desc) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(desc); - sg_shader_desc desc_def = _sg_shader_desc_defaults(desc); - sg_shader shd_id = _sg_alloc_shader(); - if (shd_id.id != SG_INVALID_ID) { - _sg_shader_t* shd = _sg_shader_at(&_sg.pools, shd_id.id); - SOKOL_ASSERT(shd && (shd->slot.state == SG_RESOURCESTATE_ALLOC)); - _sg_init_shader(shd, &desc_def); - SOKOL_ASSERT((shd->slot.state == SG_RESOURCESTATE_VALID) || (shd->slot.state == SG_RESOURCESTATE_FAILED)); - } - _SG_TRACE_ARGS(make_shader, &desc_def, shd_id); - return shd_id; -} - -SOKOL_API_IMPL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(desc); - sg_pipeline_desc desc_def = _sg_pipeline_desc_defaults(desc); - sg_pipeline pip_id = _sg_alloc_pipeline(); - if (pip_id.id != SG_INVALID_ID) { - _sg_pipeline_t* pip = _sg_pipeline_at(&_sg.pools, pip_id.id); - SOKOL_ASSERT(pip && (pip->slot.state == SG_RESOURCESTATE_ALLOC)); - _sg_init_pipeline(pip, &desc_def); - SOKOL_ASSERT((pip->slot.state == SG_RESOURCESTATE_VALID) || (pip->slot.state == SG_RESOURCESTATE_FAILED)); - } - _SG_TRACE_ARGS(make_pipeline, &desc_def, pip_id); - return pip_id; -} - -SOKOL_API_IMPL sg_attachments sg_make_attachments(const sg_attachments_desc* desc) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(desc); - sg_attachments_desc desc_def = _sg_attachments_desc_defaults(desc); - sg_attachments atts_id = _sg_alloc_attachments(); - if (atts_id.id != SG_INVALID_ID) { - _sg_attachments_t* atts = _sg_attachments_at(&_sg.pools, atts_id.id); - SOKOL_ASSERT(atts && (atts->slot.state == SG_RESOURCESTATE_ALLOC)); - _sg_init_attachments(atts, &desc_def); - SOKOL_ASSERT((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED)); - } - _SG_TRACE_ARGS(make_attachments, &desc_def, atts_id); - return atts_id; -} - -SOKOL_API_IMPL void sg_destroy_buffer(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - _SG_TRACE_ARGS(destroy_buffer, buf_id); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - if ((buf->slot.state == SG_RESOURCESTATE_VALID) || (buf->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_buffer(buf); - SOKOL_ASSERT(buf->slot.state == SG_RESOURCESTATE_ALLOC); - } - if (buf->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_buffer(buf); - SOKOL_ASSERT(buf->slot.state == SG_RESOURCESTATE_INITIAL); - } - } -} - -SOKOL_API_IMPL void sg_destroy_image(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - _SG_TRACE_ARGS(destroy_image, img_id); - _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - if ((img->slot.state == SG_RESOURCESTATE_VALID) || (img->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_image(img); - SOKOL_ASSERT(img->slot.state == SG_RESOURCESTATE_ALLOC); - } - if (img->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_image(img); - SOKOL_ASSERT(img->slot.state == SG_RESOURCESTATE_INITIAL); - } - } -} - -SOKOL_API_IMPL void sg_destroy_sampler(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - _SG_TRACE_ARGS(destroy_sampler, smp_id); - _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - if ((smp->slot.state == SG_RESOURCESTATE_VALID) || (smp->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_sampler(smp); - SOKOL_ASSERT(smp->slot.state == SG_RESOURCESTATE_ALLOC); - } - if (smp->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_sampler(smp); - SOKOL_ASSERT(smp->slot.state == SG_RESOURCESTATE_INITIAL); - } - } -} - -SOKOL_API_IMPL void sg_destroy_shader(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - _SG_TRACE_ARGS(destroy_shader, shd_id); - _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - if ((shd->slot.state == SG_RESOURCESTATE_VALID) || (shd->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_shader(shd); - SOKOL_ASSERT(shd->slot.state == SG_RESOURCESTATE_ALLOC); - } - if (shd->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_shader(shd); - SOKOL_ASSERT(shd->slot.state == SG_RESOURCESTATE_INITIAL); - } - } -} - -SOKOL_API_IMPL void sg_destroy_pipeline(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - _SG_TRACE_ARGS(destroy_pipeline, pip_id); - _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - if ((pip->slot.state == SG_RESOURCESTATE_VALID) || (pip->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_pipeline(pip); - SOKOL_ASSERT(pip->slot.state == SG_RESOURCESTATE_ALLOC); - } - if (pip->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_pipeline(pip); - SOKOL_ASSERT(pip->slot.state == SG_RESOURCESTATE_INITIAL); - } - } -} - -SOKOL_API_IMPL void sg_destroy_attachments(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - _SG_TRACE_ARGS(destroy_attachments, atts_id); - _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - if ((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_attachments(atts); - SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_ALLOC); - } - if (atts->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_attachments(atts); - SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_INITIAL); - } - } -} - -SOKOL_API_IMPL void sg_begin_pass(const sg_pass* pass) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(!_sg.cur_pass.valid); - SOKOL_ASSERT(!_sg.cur_pass.in_pass); - SOKOL_ASSERT(pass); - SOKOL_ASSERT((pass->_start_canary == 0) && (pass->_end_canary == 0)); - const sg_pass pass_def = _sg_pass_defaults(pass); - if (!_sg_validate_begin_pass(&pass_def)) { - return; - } - if (pass_def.attachments.id != SG_INVALID_ID) { - // an offscreen pass - SOKOL_ASSERT(_sg.cur_pass.atts == 0); - _sg.cur_pass.atts = _sg_lookup_attachments(&_sg.pools, pass_def.attachments.id); - if (0 == _sg.cur_pass.atts) { - _SG_ERROR(BEGINPASS_ATTACHMENT_INVALID); - return; - } - _sg.cur_pass.atts_id = pass_def.attachments; - _sg.cur_pass.width = _sg.cur_pass.atts->cmn.width; - _sg.cur_pass.height = _sg.cur_pass.atts->cmn.height; - } else { - // a swapchain pass - SOKOL_ASSERT(pass_def.swapchain.width > 0); - SOKOL_ASSERT(pass_def.swapchain.height > 0); - SOKOL_ASSERT(pass_def.swapchain.color_format > SG_PIXELFORMAT_NONE); - SOKOL_ASSERT(pass_def.swapchain.sample_count > 0); - _sg.cur_pass.width = pass_def.swapchain.width; - _sg.cur_pass.height = pass_def.swapchain.height; - _sg.cur_pass.swapchain.color_fmt = pass_def.swapchain.color_format; - _sg.cur_pass.swapchain.depth_fmt = pass_def.swapchain.depth_format; - _sg.cur_pass.swapchain.sample_count = pass_def.swapchain.sample_count; - } - _sg.cur_pass.valid = true; // may be overruled by backend begin-pass functions - _sg.cur_pass.in_pass = true; - _sg_begin_pass(&pass_def); - _SG_TRACE_ARGS(begin_pass, &pass_def); -} - -SOKOL_API_IMPL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(_sg.cur_pass.in_pass); - _sg_stats_add(num_apply_viewport, 1); - if (!_sg.cur_pass.valid) { - return; - } - _sg_apply_viewport(x, y, width, height, origin_top_left); - _SG_TRACE_ARGS(apply_viewport, x, y, width, height, origin_top_left); -} - -SOKOL_API_IMPL void sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left) { - sg_apply_viewport((int)x, (int)y, (int)width, (int)height, origin_top_left); -} - -SOKOL_API_IMPL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(_sg.cur_pass.in_pass); - _sg_stats_add(num_apply_scissor_rect, 1); - if (!_sg.cur_pass.valid) { - return; - } - _sg_apply_scissor_rect(x, y, width, height, origin_top_left); - _SG_TRACE_ARGS(apply_scissor_rect, x, y, width, height, origin_top_left); -} - -SOKOL_API_IMPL void sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left) { - sg_apply_scissor_rect((int)x, (int)y, (int)width, (int)height, origin_top_left); -} - -SOKOL_API_IMPL void sg_apply_pipeline(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(_sg.cur_pass.in_pass); - _sg_stats_add(num_apply_pipeline, 1); - if (!_sg_validate_apply_pipeline(pip_id)) { - _sg.next_draw_valid = false; - return; - } - if (!_sg.cur_pass.valid) { - return; - } - _sg.cur_pipeline = pip_id; - _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - SOKOL_ASSERT(pip); - _sg.next_draw_valid = (SG_RESOURCESTATE_VALID == pip->slot.state); - SOKOL_ASSERT(pip->shader && (pip->shader->slot.id == pip->cmn.shader_id.id)); - _sg_apply_pipeline(pip); - _SG_TRACE_ARGS(apply_pipeline, pip_id); -} - -SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(_sg.cur_pass.in_pass); - SOKOL_ASSERT(bindings); - SOKOL_ASSERT((bindings->_start_canary == 0) && (bindings->_end_canary==0)); - _sg_stats_add(num_apply_bindings, 1); - if (!_sg_validate_apply_bindings(bindings)) { - _sg.next_draw_valid = false; - return; - } - if (!_sg.cur_pass.valid) { - return; - } - - _sg_bindings_t bnd; - _sg_clear(&bnd, sizeof(bnd)); - bnd.pip = _sg_lookup_pipeline(&_sg.pools, _sg.cur_pipeline.id); - if (0 == bnd.pip) { - _sg.next_draw_valid = false; - } - - for (int i = 0; i < SG_MAX_VERTEX_BUFFERS; i++, bnd.num_vbs++) { - if (bindings->vertex_buffers[i].id) { - bnd.vbs[i] = _sg_lookup_buffer(&_sg.pools, bindings->vertex_buffers[i].id); - bnd.vb_offsets[i] = bindings->vertex_buffer_offsets[i]; - if (bnd.vbs[i]) { - _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.vbs[i]->slot.state); - _sg.next_draw_valid &= !bnd.vbs[i]->cmn.append_overflow; - } else { - _sg.next_draw_valid = false; - } - } else { - break; - } - } - - if (bindings->index_buffer.id) { - bnd.ib = _sg_lookup_buffer(&_sg.pools, bindings->index_buffer.id); - bnd.ib_offset = bindings->index_buffer_offset; - if (bnd.ib) { - _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.ib->slot.state); - _sg.next_draw_valid &= !bnd.ib->cmn.append_overflow; - } else { - _sg.next_draw_valid = false; - } - } - - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++, bnd.num_vs_imgs++) { - if (bindings->vs.images[i].id) { - bnd.vs_imgs[i] = _sg_lookup_image(&_sg.pools, bindings->vs.images[i].id); - if (bnd.vs_imgs[i]) { - _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.vs_imgs[i]->slot.state); - } else { - _sg.next_draw_valid = false; - } - } else { - break; - } - } - - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++, bnd.num_vs_smps++) { - if (bindings->vs.samplers[i].id) { - bnd.vs_smps[i] = _sg_lookup_sampler(&_sg.pools, bindings->vs.samplers[i].id); - if (bnd.vs_smps[i]) { - _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.vs_smps[i]->slot.state); - } else { - _sg.next_draw_valid = false; - } - } else { - break; - } - } - - for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++, bnd.num_vs_sbufs++) { - if (bindings->vs.storage_buffers[i].id) { - bnd.vs_sbufs[i] = _sg_lookup_buffer(&_sg.pools, bindings->vs.storage_buffers[i].id); - if (bnd.vs_sbufs[i]) { - _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.vs_sbufs[i]->slot.state); - } else { - _sg.next_draw_valid = false; - } - } else { - break; - } - } - - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++, bnd.num_fs_imgs++) { - if (bindings->fs.images[i].id) { - bnd.fs_imgs[i] = _sg_lookup_image(&_sg.pools, bindings->fs.images[i].id); - if (bnd.fs_imgs[i]) { - _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.fs_imgs[i]->slot.state); - } else { - _sg.next_draw_valid = false; - } - } else { - break; - } - } - - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++, bnd.num_fs_smps++) { - if (bindings->fs.samplers[i].id) { - bnd.fs_smps[i] = _sg_lookup_sampler(&_sg.pools, bindings->fs.samplers[i].id); - if (bnd.fs_smps[i]) { - _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.fs_smps[i]->slot.state); - } else { - _sg.next_draw_valid = false; - } - } else { - break; - } - } - - for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++, bnd.num_fs_sbufs++) { - if (bindings->fs.storage_buffers[i].id) { - bnd.fs_sbufs[i] = _sg_lookup_buffer(&_sg.pools, bindings->fs.storage_buffers[i].id); - if (bnd.fs_sbufs[i]) { - _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.fs_sbufs[i]->slot.state); - } else { - _sg.next_draw_valid = false; - } - } else { - break; - } - } - if (_sg.next_draw_valid) { - _sg.next_draw_valid &= _sg_apply_bindings(&bnd); - _SG_TRACE_ARGS(apply_bindings, bindings); - } -} - -SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(_sg.cur_pass.in_pass); - SOKOL_ASSERT((stage == SG_SHADERSTAGE_VS) || (stage == SG_SHADERSTAGE_FS)); - SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); - SOKOL_ASSERT(data && data->ptr && (data->size > 0)); - _sg_stats_add(num_apply_uniforms, 1); - _sg_stats_add(size_apply_uniforms, (uint32_t)data->size); - if (!_sg_validate_apply_uniforms(stage, ub_index, data)) { - _sg.next_draw_valid = false; - return; - } - if (!_sg.cur_pass.valid) { - return; - } - if (!_sg.next_draw_valid) { - return; - } - _sg_apply_uniforms(stage, ub_index, data); - _SG_TRACE_ARGS(apply_uniforms, stage, ub_index, data); -} - -SOKOL_API_IMPL void sg_draw(int base_element, int num_elements, int num_instances) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(_sg.cur_pass.in_pass); - SOKOL_ASSERT(base_element >= 0); - SOKOL_ASSERT(num_elements >= 0); - SOKOL_ASSERT(num_instances >= 0); - _sg_stats_add(num_draw, 1); - _sg_stats_add(num_verts, num_elements*num_instances); - if (!_sg.cur_pass.valid) { - return; - } - if (!_sg.next_draw_valid) { - return; - } - /* attempting to draw with zero elements or instances is not technically an - error, but might be handled as an error in the backend API (e.g. on Metal) - */ - if ((0 == num_elements) || (0 == num_instances)) { - return; - } - _sg_draw(base_element, num_elements, num_instances); - _SG_TRACE_ARGS(draw, base_element, num_elements, num_instances); -} - -SOKOL_API_IMPL void sg_end_pass(void) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(_sg.cur_pass.in_pass); - _sg_stats_add(num_passes, 1); - // NOTE: don't exit early if !_sg.cur_pass.valid - _sg_end_pass(); - _sg.cur_pipeline.id = SG_INVALID_ID; - _sg_clear(&_sg.cur_pass, sizeof(_sg.cur_pass)); - _SG_TRACE_NOARGS(end_pass); -} - -SOKOL_API_IMPL void sg_commit(void) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(!_sg.cur_pass.valid); - SOKOL_ASSERT(!_sg.cur_pass.in_pass); - _sg_commit(); - _sg.stats.frame_index = _sg.frame_index; - _sg.prev_stats = _sg.stats; - _sg_clear(&_sg.stats, sizeof(_sg.stats)); - _sg_notify_commit_listeners(); - _SG_TRACE_NOARGS(commit); - _sg.frame_index++; -} - -SOKOL_API_IMPL void sg_reset_state_cache(void) { - SOKOL_ASSERT(_sg.valid); - _sg_reset_state_cache(); - _SG_TRACE_NOARGS(reset_state_cache); -} - -SOKOL_API_IMPL void sg_update_buffer(sg_buffer buf_id, const sg_range* data) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(data && data->ptr && (data->size > 0)); - _sg_stats_add(num_update_buffer, 1); - _sg_stats_add(size_update_buffer, (uint32_t)data->size); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if ((data->size > 0) && buf && (buf->slot.state == SG_RESOURCESTATE_VALID)) { - if (_sg_validate_update_buffer(buf, data)) { - SOKOL_ASSERT(data->size <= (size_t)buf->cmn.size); - // only one update allowed per buffer and frame - SOKOL_ASSERT(buf->cmn.update_frame_index != _sg.frame_index); - // update and append on same buffer in same frame not allowed - SOKOL_ASSERT(buf->cmn.append_frame_index != _sg.frame_index); - _sg_update_buffer(buf, data); - buf->cmn.update_frame_index = _sg.frame_index; - } - } - _SG_TRACE_ARGS(update_buffer, buf_id, data); -} - -SOKOL_API_IMPL int sg_append_buffer(sg_buffer buf_id, const sg_range* data) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(data && data->ptr); - _sg_stats_add(num_append_buffer, 1); - _sg_stats_add(size_append_buffer, (uint32_t)data->size); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - int result; - if (buf) { - // rewind append cursor in a new frame - if (buf->cmn.append_frame_index != _sg.frame_index) { - buf->cmn.append_pos = 0; - buf->cmn.append_overflow = false; - } - if (((size_t)buf->cmn.append_pos + data->size) > (size_t)buf->cmn.size) { - buf->cmn.append_overflow = true; - } - const int start_pos = buf->cmn.append_pos; - // NOTE: the multiple-of-4 requirement for the buffer offset is coming - // from WebGPU, but we want identical behaviour between backends - SOKOL_ASSERT(_sg_multiple_u64((uint64_t)start_pos, 4)); - if (buf->slot.state == SG_RESOURCESTATE_VALID) { - if (_sg_validate_append_buffer(buf, data)) { - if (!buf->cmn.append_overflow && (data->size > 0)) { - // update and append on same buffer in same frame not allowed - SOKOL_ASSERT(buf->cmn.update_frame_index != _sg.frame_index); - _sg_append_buffer(buf, data, buf->cmn.append_frame_index != _sg.frame_index); - buf->cmn.append_pos += (int) _sg_roundup_u64(data->size, 4); - buf->cmn.append_frame_index = _sg.frame_index; - } - } - } - result = start_pos; - } else { - // FIXME: should we return -1 here? - result = 0; - } - _SG_TRACE_ARGS(append_buffer, buf_id, data, result); - return result; -} - -SOKOL_API_IMPL bool sg_query_buffer_overflow(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - bool result = buf ? buf->cmn.append_overflow : false; - return result; -} - -SOKOL_API_IMPL bool sg_query_buffer_will_overflow(sg_buffer buf_id, size_t size) { - SOKOL_ASSERT(_sg.valid); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - bool result = false; - if (buf) { - int append_pos = buf->cmn.append_pos; - // rewind append cursor in a new frame - if (buf->cmn.append_frame_index != _sg.frame_index) { - append_pos = 0; - } - if ((append_pos + _sg_roundup((int)size, 4)) > buf->cmn.size) { - result = true; - } - } - return result; -} - -SOKOL_API_IMPL void sg_update_image(sg_image img_id, const sg_image_data* data) { - SOKOL_ASSERT(_sg.valid); - _sg_stats_add(num_update_image, 1); - for (int face_index = 0; face_index < SG_CUBEFACE_NUM; face_index++) { - for (int mip_index = 0; mip_index < SG_MAX_MIPMAPS; mip_index++) { - if (data->subimage[face_index][mip_index].size == 0) { - break; - } - _sg_stats_add(size_update_image, (uint32_t)data->subimage[face_index][mip_index].size); - } - } - _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img && img->slot.state == SG_RESOURCESTATE_VALID) { - if (_sg_validate_update_image(img, data)) { - SOKOL_ASSERT(img->cmn.upd_frame_index != _sg.frame_index); - _sg_update_image(img, data); - img->cmn.upd_frame_index = _sg.frame_index; - } - } - _SG_TRACE_ARGS(update_image, img_id, data); -} - -SOKOL_API_IMPL void sg_push_debug_group(const char* name) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(name); - _sg_push_debug_group(name); - _SG_TRACE_ARGS(push_debug_group, name); -} - -SOKOL_API_IMPL void sg_pop_debug_group(void) { - SOKOL_ASSERT(_sg.valid); - _sg_pop_debug_group(); - _SG_TRACE_NOARGS(pop_debug_group); -} - -SOKOL_API_IMPL bool sg_add_commit_listener(sg_commit_listener listener) { - SOKOL_ASSERT(_sg.valid); - return _sg_add_commit_listener(&listener); -} - -SOKOL_API_IMPL bool sg_remove_commit_listener(sg_commit_listener listener) { - SOKOL_ASSERT(_sg.valid); - return _sg_remove_commit_listener(&listener); -} - -SOKOL_API_IMPL void sg_enable_frame_stats(void) { - SOKOL_ASSERT(_sg.valid); - _sg.stats_enabled = true; -} - -SOKOL_API_IMPL void sg_disable_frame_stats(void) { - SOKOL_ASSERT(_sg.valid); - _sg.stats_enabled = false; -} - -SOKOL_API_IMPL bool sg_frame_stats_enabled(void) { - return _sg.stats_enabled; -} - -SOKOL_API_IMPL sg_buffer_info sg_query_buffer_info(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - sg_buffer_info info; - _sg_clear(&info, sizeof(info)); - const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - info.slot.state = buf->slot.state; - info.slot.res_id = buf->slot.id; - info.update_frame_index = buf->cmn.update_frame_index; - info.append_frame_index = buf->cmn.append_frame_index; - info.append_pos = buf->cmn.append_pos; - info.append_overflow = buf->cmn.append_overflow; - #if defined(SOKOL_D3D11) - info.num_slots = 1; - info.active_slot = 0; - #else - info.num_slots = buf->cmn.num_slots; - info.active_slot = buf->cmn.active_slot; - #endif - } - return info; -} - -SOKOL_API_IMPL sg_image_info sg_query_image_info(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - sg_image_info info; - _sg_clear(&info, sizeof(info)); - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - info.slot.state = img->slot.state; - info.slot.res_id = img->slot.id; - info.upd_frame_index = img->cmn.upd_frame_index; - #if defined(SOKOL_D3D11) - info.num_slots = 1; - info.active_slot = 0; - #else - info.num_slots = img->cmn.num_slots; - info.active_slot = img->cmn.active_slot; - #endif - } - return info; -} - -SOKOL_API_IMPL sg_sampler_info sg_query_sampler_info(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - sg_sampler_info info; - _sg_clear(&info, sizeof(info)); - const _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - info.slot.state = smp->slot.state; - info.slot.res_id = smp->slot.id; - } - return info; -} - -SOKOL_API_IMPL sg_shader_info sg_query_shader_info(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - sg_shader_info info; - _sg_clear(&info, sizeof(info)); - const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - info.slot.state = shd->slot.state; - info.slot.res_id = shd->slot.id; - } - return info; -} - -SOKOL_API_IMPL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - sg_pipeline_info info; - _sg_clear(&info, sizeof(info)); - const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - info.slot.state = pip->slot.state; - info.slot.res_id = pip->slot.id; - } - return info; -} - -SOKOL_API_IMPL sg_attachments_info sg_query_attachments_info(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - sg_attachments_info info; - _sg_clear(&info, sizeof(info)); - const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - info.slot.state = atts->slot.state; - info.slot.res_id = atts->slot.id; - } - return info; -} - -SOKOL_API_IMPL sg_buffer_desc sg_query_buffer_desc(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - sg_buffer_desc desc; - _sg_clear(&desc, sizeof(desc)); - const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - desc.size = (size_t)buf->cmn.size; - desc.type = buf->cmn.type; - desc.usage = buf->cmn.usage; - } - return desc; -} - -SOKOL_API_IMPL sg_image_desc sg_query_image_desc(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - sg_image_desc desc; - _sg_clear(&desc, sizeof(desc)); - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - desc.type = img->cmn.type; - desc.render_target = img->cmn.render_target; - desc.width = img->cmn.width; - desc.height = img->cmn.height; - desc.num_slices = img->cmn.num_slices; - desc.num_mipmaps = img->cmn.num_mipmaps; - desc.usage = img->cmn.usage; - desc.pixel_format = img->cmn.pixel_format; - desc.sample_count = img->cmn.sample_count; - } - return desc; -} - -SOKOL_API_IMPL sg_sampler_desc sg_query_sampler_desc(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - sg_sampler_desc desc; - _sg_clear(&desc, sizeof(desc)); - const _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - desc.min_filter = smp->cmn.min_filter; - desc.mag_filter = smp->cmn.mag_filter; - desc.mipmap_filter = smp->cmn.mipmap_filter; - desc.wrap_u = smp->cmn.wrap_u; - desc.wrap_v = smp->cmn.wrap_v; - desc.wrap_w = smp->cmn.wrap_w; - desc.min_lod = smp->cmn.min_lod; - desc.max_lod = smp->cmn.max_lod; - desc.border_color = smp->cmn.border_color; - desc.compare = smp->cmn.compare; - desc.max_anisotropy = smp->cmn.max_anisotropy; - } - return desc; -} - -SOKOL_API_IMPL sg_shader_desc sg_query_shader_desc(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - sg_shader_desc desc; - _sg_clear(&desc, sizeof(desc)); - const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - for (int stage_idx = 0; stage_idx < SG_NUM_SHADER_STAGES; stage_idx++) { - sg_shader_stage_desc* stage_desc = (stage_idx == 0) ? &desc.vs : &desc.fs; - const _sg_shader_stage_t* stage = &shd->cmn.stage[stage_idx]; - for (int ub_idx = 0; ub_idx < stage->num_uniform_blocks; ub_idx++) { - sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_idx]; - const _sg_shader_uniform_block_t* ub = &stage->uniform_blocks[ub_idx]; - ub_desc->size = ub->size; - } - for (int img_idx = 0; img_idx < stage->num_images; img_idx++) { - sg_shader_image_desc* img_desc = &stage_desc->images[img_idx]; - const _sg_shader_image_t* img = &stage->images[img_idx]; - img_desc->used = true; - img_desc->image_type = img->image_type; - img_desc->sample_type = img->sample_type; - img_desc->multisampled = img->multisampled; - } - for (int smp_idx = 0; smp_idx < stage->num_samplers; smp_idx++) { - sg_shader_sampler_desc* smp_desc = &stage_desc->samplers[smp_idx]; - const _sg_shader_sampler_t* smp = &stage->samplers[smp_idx]; - smp_desc->used = true; - smp_desc->sampler_type = smp->sampler_type; - } - for (int img_smp_idx = 0; img_smp_idx < stage->num_image_samplers; img_smp_idx++) { - sg_shader_image_sampler_pair_desc* img_smp_desc = &stage_desc->image_sampler_pairs[img_smp_idx]; - const _sg_shader_image_sampler_t* img_smp = &stage->image_samplers[img_smp_idx]; - img_smp_desc->used = true; - img_smp_desc->image_slot = img_smp->image_slot; - img_smp_desc->sampler_slot = img_smp->sampler_slot; - img_smp_desc->glsl_name = 0; - } - } - } - return desc; -} - -SOKOL_API_IMPL sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - sg_pipeline_desc desc; - _sg_clear(&desc, sizeof(desc)); - const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - desc.shader = pip->cmn.shader_id; - desc.layout = pip->cmn.layout; - desc.depth = pip->cmn.depth; - desc.stencil = pip->cmn.stencil; - desc.color_count = pip->cmn.color_count; - for (int i = 0; i < pip->cmn.color_count; i++) { - desc.colors[i] = pip->cmn.colors[i]; - } - desc.primitive_type = pip->cmn.primitive_type; - desc.index_type = pip->cmn.index_type; - desc.cull_mode = pip->cmn.cull_mode; - desc.face_winding = pip->cmn.face_winding; - desc.sample_count = pip->cmn.sample_count; - desc.blend_color = pip->cmn.blend_color; - desc.alpha_to_coverage_enabled = pip->cmn.alpha_to_coverage_enabled; - } - return desc; -} - -SOKOL_API_IMPL sg_attachments_desc sg_query_attachments_desc(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - sg_attachments_desc desc; - _sg_clear(&desc, sizeof(desc)); - const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - for (int i = 0; i < atts->cmn.num_colors; i++) { - desc.colors[i].image = atts->cmn.colors[i].image_id; - desc.colors[i].mip_level = atts->cmn.colors[i].mip_level; - desc.colors[i].slice = atts->cmn.colors[i].slice; - } - desc.depth_stencil.image = atts->cmn.depth_stencil.image_id; - desc.depth_stencil.mip_level = atts->cmn.depth_stencil.mip_level; - desc.depth_stencil.slice = atts->cmn.depth_stencil.slice; - } - return desc; -} - -SOKOL_API_IMPL sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc) { - SOKOL_ASSERT(_sg.valid && desc); - return _sg_buffer_desc_defaults(desc); -} - -SOKOL_API_IMPL sg_image_desc sg_query_image_defaults(const sg_image_desc* desc) { - SOKOL_ASSERT(_sg.valid && desc); - return _sg_image_desc_defaults(desc); -} - -SOKOL_API_IMPL sg_sampler_desc sg_query_sampler_defaults(const sg_sampler_desc* desc) { - SOKOL_ASSERT(_sg.valid && desc); - return _sg_sampler_desc_defaults(desc); -} - -SOKOL_API_IMPL sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc) { - SOKOL_ASSERT(_sg.valid && desc); - return _sg_shader_desc_defaults(desc); -} - -SOKOL_API_IMPL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc) { - SOKOL_ASSERT(_sg.valid && desc); - return _sg_pipeline_desc_defaults(desc); -} - -SOKOL_API_IMPL sg_attachments_desc sg_query_attachments_defaults(const sg_attachments_desc* desc) { - SOKOL_ASSERT(_sg.valid && desc); - return _sg_attachments_desc_defaults(desc); -} - -SOKOL_API_IMPL const void* sg_d3d11_device(void) { - #if defined(SOKOL_D3D11) - return (const void*) _sg.d3d11.dev; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sg_d3d11_device_context(void) { - #if defined(SOKOL_D3D11) - return (const void*) _sg.d3d11.ctx; - #else - return 0; - #endif -} - -SOKOL_API_IMPL sg_d3d11_buffer_info sg_d3d11_query_buffer_info(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - sg_d3d11_buffer_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_D3D11) - const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - res.buf = (const void*) buf->d3d11.buf; - } - #else - _SOKOL_UNUSED(buf_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_d3d11_image_info sg_d3d11_query_image_info(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - sg_d3d11_image_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_D3D11) - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - res.tex2d = (const void*) img->d3d11.tex2d; - res.tex3d = (const void*) img->d3d11.tex3d; - res.res = (const void*) img->d3d11.res; - res.srv = (const void*) img->d3d11.srv; - } - #else - _SOKOL_UNUSED(img_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_d3d11_sampler_info sg_d3d11_query_sampler_info(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - sg_d3d11_sampler_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_D3D11) - const _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - res.smp = (const void*) smp->d3d11.smp; - } - #else - _SOKOL_UNUSED(smp_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_d3d11_shader_info sg_d3d11_query_shader_info(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - sg_d3d11_shader_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_D3D11) - const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - for (int i = 0; i < SG_MAX_SHADERSTAGE_UBS; i++) { - res.vs_cbufs[i] = (const void*) shd->d3d11.stage[SG_SHADERSTAGE_VS].cbufs[i]; - res.fs_cbufs[i] = (const void*) shd->d3d11.stage[SG_SHADERSTAGE_FS].cbufs[i]; - } - res.vs = (const void*) shd->d3d11.vs; - res.fs = (const void*) shd->d3d11.fs; - } - #else - _SOKOL_UNUSED(shd_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_d3d11_pipeline_info sg_d3d11_query_pipeline_info(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - sg_d3d11_pipeline_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_D3D11) - const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - res.il = (const void*) pip->d3d11.il; - res.rs = (const void*) pip->d3d11.rs; - res.dss = (const void*) pip->d3d11.dss; - res.bs = (const void*) pip->d3d11.bs; - } - #else - _SOKOL_UNUSED(pip_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_d3d11_attachments_info sg_d3d11_query_attachments_info(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - sg_d3d11_attachments_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_D3D11) - const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - res.color_rtv[i] = (const void*) atts->d3d11.colors[i].view.rtv; - res.resolve_rtv[i] = (const void*) atts->d3d11.resolves[i].view.rtv; - } - res.dsv = (const void*) atts->d3d11.depth_stencil.view.dsv; - } - #else - _SOKOL_UNUSED(atts_id); - #endif - return res; -} - -SOKOL_API_IMPL const void* sg_mtl_device(void) { - #if defined(SOKOL_METAL) - if (nil != _sg.mtl.device) { - return (__bridge const void*) _sg.mtl.device; - } else { - return 0; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sg_mtl_render_command_encoder(void) { - #if defined(SOKOL_METAL) - if (nil != _sg.mtl.cmd_encoder) { - return (__bridge const void*) _sg.mtl.cmd_encoder; - } else { - return 0; - } - #else - return 0; - #endif -} - -SOKOL_API_IMPL sg_mtl_buffer_info sg_mtl_query_buffer_info(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - sg_mtl_buffer_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_METAL) - const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - if (buf->mtl.buf[i] != 0) { - res.buf[i] = (__bridge void*) _sg_mtl_id(buf->mtl.buf[i]); - } - } - res.active_slot = buf->cmn.active_slot; - } - #else - _SOKOL_UNUSED(buf_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_mtl_image_info sg_mtl_query_image_info(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - sg_mtl_image_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_METAL) - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - if (img->mtl.tex[i] != 0) { - res.tex[i] = (__bridge void*) _sg_mtl_id(img->mtl.tex[i]); - } - } - res.active_slot = img->cmn.active_slot; - } - #else - _SOKOL_UNUSED(img_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_mtl_sampler_info sg_mtl_query_sampler_info(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - sg_mtl_sampler_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_METAL) - const _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - if (smp->mtl.sampler_state != 0) { - res.smp = (__bridge void*) _sg_mtl_id(smp->mtl.sampler_state); - } - } - #else - _SOKOL_UNUSED(smp_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_mtl_shader_info sg_mtl_query_shader_info(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - sg_mtl_shader_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_METAL) - const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - const int vs_lib = shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_lib; - const int vs_func = shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func; - const int fs_lib = shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_lib; - const int fs_func = shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func; - if (vs_lib != 0) { - res.vs_lib = (__bridge void*) _sg_mtl_id(vs_lib); - } - if (fs_lib != 0) { - res.fs_lib = (__bridge void*) _sg_mtl_id(fs_lib); - } - if (vs_func != 0) { - res.vs_func = (__bridge void*) _sg_mtl_id(vs_func); - } - if (fs_func != 0) { - res.fs_func = (__bridge void*) _sg_mtl_id(fs_func); - } - } - #else - _SOKOL_UNUSED(shd_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_mtl_pipeline_info sg_mtl_query_pipeline_info(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - sg_mtl_pipeline_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_METAL) - const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - if (pip->mtl.rps != 0) { - res.rps = (__bridge void*) _sg_mtl_id(pip->mtl.rps); - } - if (pip->mtl.dss != 0) { - res.dss = (__bridge void*) _sg_mtl_id(pip->mtl.dss); - } - } - #else - _SOKOL_UNUSED(pip_id); - #endif - return res; -} - -SOKOL_API_IMPL const void* sg_wgpu_device(void) { - #if defined(SOKOL_WGPU) - return (const void*) _sg.wgpu.dev; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sg_wgpu_queue(void) { - #if defined(SOKOL_WGPU) - return (const void*) _sg.wgpu.queue; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sg_wgpu_command_encoder(void) { - #if defined(SOKOL_WGPU) - return (const void*) _sg.wgpu.cmd_enc; - #else - return 0; - #endif -} - -SOKOL_API_IMPL const void* sg_wgpu_render_pass_encoder(void) { - #if defined(SOKOL_WGPU) - return (const void*) _sg.wgpu.pass_enc; - #else - return 0; - #endif -} - -SOKOL_API_IMPL sg_wgpu_buffer_info sg_wgpu_query_buffer_info(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - sg_wgpu_buffer_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_WGPU) - const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - res.buf = (const void*) buf->wgpu.buf; - } - #else - _SOKOL_UNUSED(buf_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_wgpu_image_info sg_wgpu_query_image_info(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - sg_wgpu_image_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_WGPU) - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - res.tex = (const void*) img->wgpu.tex; - res.view = (const void*) img->wgpu.view; - } - #else - _SOKOL_UNUSED(img_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_wgpu_sampler_info sg_wgpu_query_sampler_info(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - sg_wgpu_sampler_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_WGPU) - const _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - res.smp = (const void*) smp->wgpu.smp; - } - #else - _SOKOL_UNUSED(smp_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_wgpu_shader_info sg_wgpu_query_shader_info(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - sg_wgpu_shader_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_WGPU) - const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - res.vs_mod = (const void*) shd->wgpu.stage[SG_SHADERSTAGE_VS].module; - res.fs_mod = (const void*) shd->wgpu.stage[SG_SHADERSTAGE_FS].module; - res.bgl = (const void*) shd->wgpu.bind_group_layout; - } - #else - _SOKOL_UNUSED(shd_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_wgpu_pipeline_info sg_wgpu_query_pipeline_info(sg_pipeline pip_id) { - SOKOL_ASSERT(_sg.valid); - sg_wgpu_pipeline_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_WGPU) - const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - res.pip = (const void*) pip->wgpu.pip; - } - #else - _SOKOL_UNUSED(pip_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_wgpu_attachments_info sg_wgpu_query_attachments_info(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - sg_wgpu_attachments_info res; - _sg_clear(&res, sizeof(res)); - #if defined(SOKOL_WGPU) - const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - res.color_view[i] = (const void*) atts->wgpu.colors[i].view; - res.resolve_view[i] = (const void*) atts->wgpu.resolves[i].view; - } - res.ds_view = (const void*) atts->wgpu.depth_stencil.view; - } - #else - _SOKOL_UNUSED(atts_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_gl_buffer_info sg_gl_query_buffer_info(sg_buffer buf_id) { - SOKOL_ASSERT(_sg.valid); - sg_gl_buffer_info res; - _sg_clear(&res, sizeof(res)); - #if defined(_SOKOL_ANY_GL) - const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - res.buf[i] = buf->gl.buf[i]; - } - res.active_slot = buf->cmn.active_slot; - } - #else - _SOKOL_UNUSED(buf_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_gl_image_info sg_gl_query_image_info(sg_image img_id) { - SOKOL_ASSERT(_sg.valid); - sg_gl_image_info res; - _sg_clear(&res, sizeof(res)); - #if defined(_SOKOL_ANY_GL) - const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - res.tex[i] = img->gl.tex[i]; - } - res.tex_target = img->gl.target; - res.msaa_render_buffer = img->gl.msaa_render_buffer; - res.active_slot = img->cmn.active_slot; - } - #else - _SOKOL_UNUSED(img_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_gl_sampler_info sg_gl_query_sampler_info(sg_sampler smp_id) { - SOKOL_ASSERT(_sg.valid); - sg_gl_sampler_info res; - _sg_clear(&res, sizeof(res)); - #if defined(_SOKOL_ANY_GL) - const _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); - if (smp) { - res.smp = smp->gl.smp; - } - #else - _SOKOL_UNUSED(smp_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_gl_shader_info sg_gl_query_shader_info(sg_shader shd_id) { - SOKOL_ASSERT(_sg.valid); - sg_gl_shader_info res; - _sg_clear(&res, sizeof(res)); - #if defined(_SOKOL_ANY_GL) - const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - res.prog = shd->gl.prog; - } - #else - _SOKOL_UNUSED(shd_id); - #endif - return res; -} - -SOKOL_API_IMPL sg_gl_attachments_info sg_gl_query_attachments_info(sg_attachments atts_id) { - SOKOL_ASSERT(_sg.valid); - sg_gl_attachments_info res; - _sg_clear(&res, sizeof(res)); - #if defined(_SOKOL_ANY_GL) - const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); - if (atts) { - res.framebuffer = atts->gl.fb; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - res.msaa_resolve_framebuffer[i] = atts->gl.msaa_resolve_framebuffer[i]; - } - } - #else - _SOKOL_UNUSED(atts_id); - #endif - return res; -} - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#endif // SOKOL_GFX_IMPL diff --git a/source/thirdparty/sokol/sokol_glue.h b/source/thirdparty/sokol/sokol_glue.h deleted file mode 100644 index a715b174..00000000 --- a/source/thirdparty/sokol/sokol_glue.h +++ /dev/null @@ -1,162 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_GLUE_IMPL) -#define SOKOL_GLUE_IMPL -#endif -#ifndef SOKOL_GLUE_INCLUDED -/* - sokol_glue.h -- glue helper functions for sokol headers - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_GLUE_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - ...optionally provide the following macros to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_GLUE_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_GLUE_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_glue.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_GLUE_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - OVERVIEW - ======== - sokol_glue.h provides glue helper functions between sokol_gfx.h and sokol_app.h, - so that sokol_gfx.h doesn't need to depend on sokol_app.h but can be - used with different window system glue libraries. - - PROVIDED FUNCTIONS - ================== - - sg_environment sglue_environment(void) - - Returns an sg_environment struct initialized by calling sokol_app.h - functions. Use this in the sg_setup() call like this: - - sg_setup(&(sg_desc){ - .environment = sglue_environment(), - ... - }); - - sg_swapchain sglue_swapchain(void) - - Returns an sg_swapchain struct initialized by calling sokol_app.h - functions. Use this in sg_begin_pass() for a 'swapchain pass' like - this: - - sg_begin_pass(&(sg_pass){ .swapchain = sglue_swapchain(), ... }); - - 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. -*/ -#define SOKOL_GLUE_INCLUDED - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_GLUE_API_DECL) -#define SOKOL_GLUE_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_GLUE_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GLUE_IMPL) -#define SOKOL_GLUE_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_GLUE_API_DECL __declspec(dllimport) -#else -#define SOKOL_GLUE_API_DECL extern -#endif -#endif - -#ifndef SOKOL_GFX_INCLUDED -#error "Please include sokol_gfx.h before sokol_glue.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -SOKOL_GLUE_API_DECL sg_environment sglue_environment(void); -SOKOL_GLUE_API_DECL sg_swapchain sglue_swapchain(void); - -#ifdef __cplusplus -} /* extern "C" */ -#endif -#endif /* SOKOL_GLUE_INCLUDED */ - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_GLUE_IMPL -#define SOKOL_GLUE_IMPL_INCLUDED (1) -#include /* memset */ - -#ifndef SOKOL_APP_INCLUDED -#error "Please include sokol_app.h before the sokol_glue.h implementation" -#endif - -#ifndef SOKOL_API_IMPL -#define SOKOL_API_IMPL -#endif - - -SOKOL_API_IMPL sg_environment sglue_environment(void) { - sg_environment env; - memset(&env, 0, sizeof(env)); - env.defaults.color_format = (sg_pixel_format) sapp_color_format(); - env.defaults.depth_format = (sg_pixel_format) sapp_depth_format(); - env.defaults.sample_count = sapp_sample_count(); - env.metal.device = sapp_metal_get_device(); - env.d3d11.device = sapp_d3d11_get_device(); - env.d3d11.device_context = sapp_d3d11_get_device_context(); - env.wgpu.device = sapp_wgpu_get_device(); - return env; -} - -SOKOL_API_IMPL sg_swapchain sglue_swapchain(void) { - sg_swapchain swapchain; - memset(&swapchain, 0, sizeof(swapchain)); - swapchain.width = sapp_width(); - swapchain.height = sapp_height(); - swapchain.sample_count = sapp_sample_count(); - swapchain.color_format = (sg_pixel_format)sapp_color_format(); - swapchain.depth_format = (sg_pixel_format)sapp_depth_format(); - swapchain.metal.current_drawable = sapp_metal_get_current_drawable(); - swapchain.metal.depth_stencil_texture = sapp_metal_get_depth_stencil_texture(); - swapchain.metal.msaa_color_texture = sapp_metal_get_msaa_color_texture(); - swapchain.d3d11.render_view = sapp_d3d11_get_render_view(); - swapchain.d3d11.resolve_view = sapp_d3d11_get_resolve_view(); - swapchain.d3d11.depth_stencil_view = sapp_d3d11_get_depth_stencil_view(); - swapchain.wgpu.render_view = sapp_wgpu_get_render_view(); - swapchain.wgpu.resolve_view = sapp_wgpu_get_resolve_view(); - swapchain.wgpu.depth_stencil_view = sapp_wgpu_get_depth_stencil_view(); - swapchain.gl.framebuffer = sapp_gl_get_framebuffer(); - return swapchain; -} - -#endif /* SOKOL_GLUE_IMPL */ diff --git a/source/thirdparty/sokol/sokol_log.h b/source/thirdparty/sokol/sokol_log.h deleted file mode 100644 index 58ff30bf..00000000 --- a/source/thirdparty/sokol/sokol_log.h +++ /dev/null @@ -1,343 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_LOG_IMPL) -#define SOKOL_LOG_IMPL -#endif -#ifndef SOKOL_LOG_INCLUDED -/* - sokol_log.h -- common logging callback for sokol headers - - Project URL: https://github.com/floooh/sokol - - Example code: https://github.com/floooh/sokol-samples - - Do this: - #define SOKOL_IMPL or - #define SOKOL_LOG_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - Optionally provide the following defines when building the implementation: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - SOKOL_LOG_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_GFX_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - Optionally define the following for verbose output: - - SOKOL_DEBUG - by default this is defined if _DEBUG is defined - - - OVERVIEW - ======== - sokol_log.h provides a default logging callback for other sokol headers. - - To use the default log callback, just include sokol_log.h and provide - a function pointer to the 'slog_func' function when setting up the - sokol library: - - For instance with sokol_audio.h: - - #include "sokol_log.h" - ... - saudio_setup(&(saudio_desc){ .logger.func = slog_func }); - - Logging output goes to stderr and/or a platform specific logging subsystem - (which means that in some scenarios you might see logging messages duplicated): - - - Windows: stderr + OutputDebugStringA() - - macOS/iOS/Linux: stderr + syslog() - - Emscripten: console.info()/warn()/error() - - Android: __android_log_write() - - On Windows with sokol_app.h also note the runtime config items to make - stdout/stderr output visible on the console for WinMain() applications - via sapp_desc.win32_console_attach or sapp_desc.win32_console_create, - however when running in a debugger on Windows, the logging output should - show up on the debug output UI panel. - - In debug mode, a log message might look like this: - - [sspine][error][id:12] /Users/floh/projects/sokol/util/sokol_spine.h:3472:0: - SKELETON_DESC_NO_ATLAS: no atlas object provided in sspine_skeleton_desc.atlas - - The source path and line number is formatted like compiler errors, in some IDEs (like VSCode) - such error messages are clickable. - - In release mode, logging is less verbose as to not bloat the executable with string data, but you still get - enough information to identify the type and location of an error: - - [sspine][error][id:12][line:3472] - - RULES FOR WRITING YOUR OWN LOGGING FUNCTION - =========================================== - - must be re-entrant because it might be called from different threads - - must treat **all** provided string pointers as optional (can be null) - - don't store the string pointers, copy the string data instead - - must not return for log level panic - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2023 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. -*/ -#define SOKOL_LOG_INCLUDED (1) -#include - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_LOG_API_DECL) -#define SOKOL_LOG_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_LOG_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_LOG_IMPL) -#define SOKOL_LOG_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_LOG_API_DECL __declspec(dllimport) -#else -#define SOKOL_LOG_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - Plug this function into the 'logger.func' struct item when initializing any of the sokol - headers. For instance for sokol_audio.h it would loom like this: - - saudio_setup(&(saudio_desc){ - .logger = { - .func = slog_func - } - }); -*/ -SOKOL_LOG_API_DECL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data); - -#ifdef __cplusplus -} // extern "C" -#endif -#endif // SOKOL_LOG_INCLUDED - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_LOG_IMPL -#define SOKOL_LOG_IMPL_INCLUDED (1) - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -#ifndef _SOKOL_UNUSED - #define _SOKOL_UNUSED(x) (void)(x) -#endif - -// platform detection -#if defined(__APPLE__) - #define _SLOG_APPLE (1) -#elif defined(__EMSCRIPTEN__) - #define _SLOG_EMSCRIPTEN (1) -#elif defined(_WIN32) - #define _SLOG_WINDOWS (1) -#elif defined(__ANDROID__) - #define _SLOG_ANDROID (1) -#elif defined(__linux__) || defined(__unix__) - #define _SLOG_LINUX (1) -#else -#error "sokol_log.h: unknown platform" -#endif - -#include // abort -#include // fputs -#include // size_t - -#if defined(_SLOG_EMSCRIPTEN) -#include -#elif defined(_SLOG_WINDOWS) -#ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN -#endif -#ifndef NOMINMAX - #define NOMINMAX -#endif -#include -#elif defined(_SLOG_ANDROID) -#include -#elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE) -#include -#endif - -// size of line buffer (on stack!) in bytes including terminating zero -#define _SLOG_LINE_LENGTH (512) - -_SOKOL_PRIVATE char* _slog_append(const char* str, char* dst, char* end) { - if (str) { - char c; - while (((c = *str++) != 0) && (dst < (end - 1))) { - *dst++ = c; - } - } - *dst = 0; - return dst; -} - -_SOKOL_PRIVATE char* _slog_itoa(uint32_t x, char* buf, size_t buf_size) { - const size_t max_digits_and_null = 11; - if (buf_size < max_digits_and_null) { - return 0; - } - char* p = buf + max_digits_and_null; - *--p = 0; - do { - *--p = '0' + (x % 10); - x /= 10; - } while (x != 0); - return p; -} - -#if defined(_SLOG_EMSCRIPTEN) -EM_JS(void, slog_js_log, (uint32_t level, const char* c_str), { - const str = UTF8ToString(c_str); - switch (level) { - case 0: console.error(str); break; - case 1: console.error(str); break; - case 2: console.warn(str); break; - default: console.info(str); break; - } -}); -#endif - -SOKOL_API_IMPL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data) { - _SOKOL_UNUSED(user_data); - - const char* log_level_str; - switch (log_level) { - case 0: log_level_str = "panic"; break; - case 1: log_level_str = "error"; break; - case 2: log_level_str = "warning"; break; - default: log_level_str = "info"; break; - } - - // build log output line - char line_buf[_SLOG_LINE_LENGTH]; - char* str = line_buf; - char* end = line_buf + sizeof(line_buf); - char num_buf[32]; - if (tag) { - str = _slog_append("[", str, end); - str = _slog_append(tag, str, end); - str = _slog_append("]", str, end); - } - str = _slog_append("[", str, end); - str = _slog_append(log_level_str, str, end); - str = _slog_append("]", str, end); - str = _slog_append("[id:", str, end); - str = _slog_append(_slog_itoa(log_item, num_buf, sizeof(num_buf)), str, end); - str = _slog_append("]", str, end); - // if a filename is provided, build a clickable log message that's compatible with compiler error messages - if (filename) { - str = _slog_append(" ", str, end); - #if defined(_MSC_VER) - // MSVC compiler error format - str = _slog_append(filename, str, end); - str = _slog_append("(", str, end); - str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end); - str = _slog_append("): ", str, end); - #else - // gcc/clang compiler error format - str = _slog_append(filename, str, end); - str = _slog_append(":", str, end); - str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end); - str = _slog_append(":0: ", str, end); - #endif - } - else { - str = _slog_append("[line:", str, end); - str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end); - str = _slog_append("] ", str, end); - } - if (message) { - str = _slog_append("\n\t", str, end); - str = _slog_append(message, str, end); - } - str = _slog_append("\n\n", str, end); - if (0 == log_level) { - str = _slog_append("ABORTING because of [panic]\n", str, end); - (void)str; - } - - // print to stderr? - #if defined(_SLOG_LINUX) || defined(_SLOG_WINDOWS) || defined(_SLOG_APPLE) - fputs(line_buf, stderr); - #endif - - // platform specific logging calls - #if defined(_SLOG_WINDOWS) - OutputDebugStringA(line_buf); - #elif defined(_SLOG_ANDROID) - int prio; - switch (log_level) { - case 0: prio = ANDROID_LOG_FATAL; break; - case 1: prio = ANDROID_LOG_ERROR; break; - case 2: prio = ANDROID_LOG_WARN; break; - default: prio = ANDROID_LOG_INFO; break; - } - __android_log_write(prio, "SOKOL", line_buf); - #elif defined(_SLOG_EMSCRIPTEN) - slog_js_log(log_level, line_buf); - #elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE) - int prio; - switch (log_level) { - case 0: prio = LOG_CRIT; break; - case 1: prio = LOG_ERR; break; - case 2: prio = LOG_WARNING; break; - default: prio = LOG_INFO; break; - } - syslog(prio, "%s", line_buf); - #endif - if (0 == log_level) { - abort(); - } -} -#endif // SOKOL_LOG_IMPL diff --git a/source/thirdparty/sokol/sokol_time.h b/source/thirdparty/sokol/sokol_time.h deleted file mode 100644 index fd766d8e..00000000 --- a/source/thirdparty/sokol/sokol_time.h +++ /dev/null @@ -1,319 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_TIME_IMPL) -#define SOKOL_TIME_IMPL -#endif -#ifndef SOKOL_TIME_INCLUDED -/* - sokol_time.h -- simple cross-platform time measurement - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_TIME_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - Optionally provide the following defines with your own implementations: - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_TIME_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_TIME_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_time.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_TIME_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - void stm_setup(); - Call once before any other functions to initialize sokol_time - (this calls for instance QueryPerformanceFrequency on Windows) - - uint64_t stm_now(); - Get current point in time in unspecified 'ticks'. The value that - is returned has no relation to the 'wall-clock' time and is - not in a specific time unit, it is only useful to compute - time differences. - - uint64_t stm_diff(uint64_t new, uint64_t old); - Computes the time difference between new and old. This will always - return a positive, non-zero value. - - uint64_t stm_since(uint64_t start); - Takes the current time, and returns the elapsed time since start - (this is a shortcut for "stm_diff(stm_now(), start)") - - uint64_t stm_laptime(uint64_t* last_time); - This is useful for measuring frame time and other recurring - events. It takes the current time, returns the time difference - to the value in last_time, and stores the current time in - last_time for the next call. If the value in last_time is 0, - the return value will be zero (this usually happens on the - very first call). - - uint64_t stm_round_to_common_refresh_rate(uint64_t duration) - This oddly named function takes a measured frame time and - returns the closest "nearby" common display refresh rate frame duration - in ticks. If the input duration isn't close to any common display - refresh rate, the input duration will be returned unchanged as a fallback. - The main purpose of this function is to remove jitter/inaccuracies from - measured frame times, and instead use the display refresh rate as - frame duration. - NOTE: for more robust frame timing, consider using the - sokol_app.h function sapp_frame_duration() - - Use the following functions to convert a duration in ticks into - useful time units: - - double stm_sec(uint64_t ticks); - double stm_ms(uint64_t ticks); - double stm_us(uint64_t ticks); - double stm_ns(uint64_t ticks); - Converts a tick value into seconds, milliseconds, microseconds - or nanoseconds. Note that not all platforms will have nanosecond - or even microsecond precision. - - Uses the following time measurement functions under the hood: - - Windows: QueryPerformanceFrequency() / QueryPerformanceCounter() - MacOS/iOS: mach_absolute_time() - emscripten: emscripten_get_now() - Linux+others: clock_gettime(CLOCK_MONOTONIC) - - 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. -*/ -#define SOKOL_TIME_INCLUDED (1) -#include - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_TIME_API_DECL) -#define SOKOL_TIME_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_TIME_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_TIME_IMPL) -#define SOKOL_TIME_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_TIME_API_DECL __declspec(dllimport) -#else -#define SOKOL_TIME_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -SOKOL_TIME_API_DECL void stm_setup(void); -SOKOL_TIME_API_DECL uint64_t stm_now(void); -SOKOL_TIME_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks); -SOKOL_TIME_API_DECL uint64_t stm_since(uint64_t start_ticks); -SOKOL_TIME_API_DECL uint64_t stm_laptime(uint64_t* last_time); -SOKOL_TIME_API_DECL uint64_t stm_round_to_common_refresh_rate(uint64_t frame_ticks); -SOKOL_TIME_API_DECL double stm_sec(uint64_t ticks); -SOKOL_TIME_API_DECL double stm_ms(uint64_t ticks); -SOKOL_TIME_API_DECL double stm_us(uint64_t ticks); -SOKOL_TIME_API_DECL double stm_ns(uint64_t ticks); - -#ifdef __cplusplus -} /* extern "C" */ -#endif -#endif // SOKOL_TIME_INCLUDED - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_TIME_IMPL -#define SOKOL_TIME_IMPL_INCLUDED (1) -#include /* memset */ - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -#if defined(_WIN32) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -typedef struct { - uint32_t initialized; - LARGE_INTEGER freq; - LARGE_INTEGER start; -} _stm_state_t; -#elif defined(__APPLE__) && defined(__MACH__) -#include -typedef struct { - uint32_t initialized; - mach_timebase_info_data_t timebase; - uint64_t start; -} _stm_state_t; -#elif defined(__EMSCRIPTEN__) -#include -typedef struct { - uint32_t initialized; - double start; -} _stm_state_t; -#else /* anything else, this will need more care for non-Linux platforms */ -#ifdef ESP8266 -// On the ESP8266, clock_gettime ignores the first argument and CLOCK_MONOTONIC isn't defined -#define CLOCK_MONOTONIC 0 -#endif -#include -typedef struct { - uint32_t initialized; - uint64_t start; -} _stm_state_t; -#endif -static _stm_state_t _stm; - -/* prevent 64-bit overflow when computing relative timestamp - see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3 -*/ -#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) -_SOKOL_PRIVATE int64_t _stm_int64_muldiv(int64_t value, int64_t numer, int64_t denom) { - int64_t q = value / denom; - int64_t r = value % denom; - return q * numer + r * numer / denom; -} -#endif - -SOKOL_API_IMPL void stm_setup(void) { - memset(&_stm, 0, sizeof(_stm)); - _stm.initialized = 0xABCDABCD; - #if defined(_WIN32) - QueryPerformanceFrequency(&_stm.freq); - QueryPerformanceCounter(&_stm.start); - #elif defined(__APPLE__) && defined(__MACH__) - mach_timebase_info(&_stm.timebase); - _stm.start = mach_absolute_time(); - #elif defined(__EMSCRIPTEN__) - _stm.start = emscripten_get_now(); - #else - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - _stm.start = (uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec; - #endif -} - -SOKOL_API_IMPL uint64_t stm_now(void) { - SOKOL_ASSERT(_stm.initialized == 0xABCDABCD); - uint64_t now; - #if defined(_WIN32) - LARGE_INTEGER qpc_t; - QueryPerformanceCounter(&qpc_t); - now = (uint64_t) _stm_int64_muldiv(qpc_t.QuadPart - _stm.start.QuadPart, 1000000000, _stm.freq.QuadPart); - #elif defined(__APPLE__) && defined(__MACH__) - const uint64_t mach_now = mach_absolute_time() - _stm.start; - now = (uint64_t) _stm_int64_muldiv((int64_t)mach_now, (int64_t)_stm.timebase.numer, (int64_t)_stm.timebase.denom); - #elif defined(__EMSCRIPTEN__) - double js_now = emscripten_get_now() - _stm.start; - now = (uint64_t) (js_now * 1000000.0); - #else - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - now = ((uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec) - _stm.start; - #endif - return now; -} - -SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks) { - if (new_ticks > old_ticks) { - return new_ticks - old_ticks; - } - else { - return 1; - } -} - -SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks) { - return stm_diff(stm_now(), start_ticks); -} - -SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) { - SOKOL_ASSERT(last_time); - uint64_t dt = 0; - uint64_t now = stm_now(); - if (0 != *last_time) { - dt = stm_diff(now, *last_time); - } - *last_time = now; - return dt; -} - -// first number is frame duration in ns, second number is tolerance in ns, -// the resulting min/max values must not overlap! -static const uint64_t _stm_refresh_rates[][2] = { - { 16666667, 1000000 }, // 60 Hz: 16.6667 +- 1ms - { 13888889, 250000 }, // 72 Hz: 13.8889 +- 0.25ms - { 13333333, 250000 }, // 75 Hz: 13.3333 +- 0.25ms - { 11764706, 250000 }, // 85 Hz: 11.7647 +- 0.25 - { 11111111, 250000 }, // 90 Hz: 11.1111 +- 0.25ms - { 10000000, 500000 }, // 100 Hz: 10.0000 +- 0.5ms - { 8333333, 500000 }, // 120 Hz: 8.3333 +- 0.5ms - { 6944445, 500000 }, // 144 Hz: 6.9445 +- 0.5ms - { 4166667, 1000000 }, // 240 Hz: 4.1666 +- 1ms - { 0, 0 }, // keep the last element always at zero -}; - -SOKOL_API_IMPL uint64_t stm_round_to_common_refresh_rate(uint64_t ticks) { - uint64_t ns; - int i = 0; - while (0 != (ns = _stm_refresh_rates[i][0])) { - uint64_t tol = _stm_refresh_rates[i][1]; - if ((ticks > (ns - tol)) && (ticks < (ns + tol))) { - return ns; - } - i++; - } - // fallthrough: didn't fit into any buckets - return ticks; -} - -SOKOL_API_IMPL double stm_sec(uint64_t ticks) { - return (double)ticks / 1000000000.0; -} - -SOKOL_API_IMPL double stm_ms(uint64_t ticks) { - return (double)ticks / 1000000.0; -} - -SOKOL_API_IMPL double stm_us(uint64_t ticks) { - return (double)ticks / 1000.0; -} - -SOKOL_API_IMPL double stm_ns(uint64_t ticks) { - return (double)ticks; -} -#endif /* SOKOL_TIME_IMPL */ - diff --git a/source/thirdparty/sokol/util/sokol_color.h b/source/thirdparty/sokol/util/sokol_color.h deleted file mode 100644 index cc31b44e..00000000 --- a/source/thirdparty/sokol/util/sokol_color.h +++ /dev/null @@ -1,1148 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_COLOR_IMPL) -#define SOKOL_COLOR_IMPL -#endif -#ifndef SOKOL_COLOR_INCLUDED -/* - sokol_color.h -- sg_color utilities - - This header was generated by gen_sokol_color.py. Do not modify it. - - Project URL: https://github.com/floooh/sokol - - Include the following headers before including sokol_color.h: - - sokol_gfx.h - - FEATURE OVERVIEW - ================ - sokol_color.h defines preset colors based on the X11 color names, - alongside utility functions to create and modify sg_color objects. - - The predefined colors are based on the X11 color names: - - https://en.wikipedia.org/wiki/X11_color_names - - This palette is useful for prototyping - lots of programmers are familiar with - these colours due to their use in X11, web development and XNA / MonoGame. They - are also handy when you want to reference a familiar color, but don't want to - write it out by hand. - - COLORS - ====== - The palette is defined using static const (or constexpr if you are using a - C++ compiler) objects. These objects use lowercase names: - - static SOKOL_COLOR_CONSTEXPR sg_color sg_red = SG_RED; - static SOKOL_COLOR_CONSTEXPR sg_color sg_green = SG_GREEN; - static SOKOL_COLOR_CONSTEXPR sg_color sg_blue = SG_BLUE; - - An sg_color preset object like sg_red can be used to initialize - an sg_pass_action: - - sg_pass_action pass_action = { - .colors[0] = { .action=SG_ACTION_CLEAR, .value = sg_red } - }; - - Initializing an object with static storage duration is more complicated - because of C language rules. Technically, a static const is not a - compile-time constant in C. To work around this, the palette is also - defined as a series of brace-enclosed list macro definitions. These - definitions use uppercase names: - - #define SG_RED { 1.0f, 0.0f, 0.0f, 1.0f } - #define SG_GREEN { 0.0f, 1.0f, 0.0f, 1.0f } - #define SG_BLUE { 0.0f, 0.0f, 1.0f, 1.0f } - - A preset macro like SG_RED can be used to initialize objects with static - storage duration: - - static struct { - sg_pass_action pass_action; - } state = { - .pass_action = { - .colors[0] = { .action = SG_ACTION_CLEAR, .value = SG_RED } - } - }; - - A second set of macro definitions exists for colors packed as 32 bit integer - values. These definitions are also uppercase, but use the _RGBA32 suffix: - - #define SG_RED_RGBA32 0xFF0000FF - #define SG_GREEN_RGBA32 0x00FF00FF - #define SG_BLUE_RGBA32 0x0000FFFF - - This is useful if your code makes use of packed colors, as sokol_gl.h does for its - internal vertex format: - - sgl_begin_triangles(); - sgl_v2f_c1i( 0.0f, 0.5f, SG_RED_RGBA32); - sgl_v2f_c1i( 0.5f, -0.5f, SG_GREEN_RGBA32); - sgl_v2f_c1i(-0.5f, -0.5f, SG_BLUE_RGBA32); - sgl_end(); - - UTILITY FUNCTIONS - ================= - - Utility functions for creating colours are provided: - - - sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) - Create a sg_color object from separate R, G, B, A bytes. - - - sg_make_color_1i(uint32_t rgba) - Create a sg_color object from RGBA bytes packed into a 32-bit unsigned integer. - - - sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount) - Linearly interpolate a color. - - - sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount) - Linearly interpolate a color. Less efficient but more precise than sg_color_lerp. - - - sg_color_multiply(const sg_color* color, float scale) - Multiply each color component by the scale factor. - - LICENSE - ======= - - zlib/libpng license - - Copyright (c) 2020 Stuart Adams - - 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. -*/ -#define SOKOL_COLOR_INCLUDED (1) - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_color.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_GL_API_DECL) -#define SOKOL_COLOR_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_COLOR_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_COLOR_IMPL) -#define SOKOL_COLOR_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_COLOR_API_DECL __declspec(dllimport) -#else -#define SOKOL_COLOR_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -#define SOKOL_COLOR_CONSTEXPR constexpr -extern "C" { -#else -#define SOKOL_COLOR_CONSTEXPR const -#endif - -SOKOL_COLOR_API_DECL sg_color sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_COLOR_API_DECL sg_color sg_make_color_1i(uint32_t rgba); -SOKOL_COLOR_API_DECL sg_color sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount); -SOKOL_COLOR_API_DECL sg_color sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount); -SOKOL_COLOR_API_DECL sg_color sg_color_multiply(const sg_color* color, float scale); - -/* Alice Blue color { R:240, G:248, B:255, A:255 } */ -#define SG_ALICE_BLUE { 0.941176471f, 0.97254902f, 1.0f, 1.0f } -/* Antique White color { R:250, G:235, B:215, A:255 } */ -#define SG_ANTIQUE_WHITE { 0.980392157f, 0.921568627f, 0.843137255f, 1.0f } -/* Aqua color { R:0, G:255, B:255, A:255 } */ -#define SG_AQUA { 0.0f, 1.0f, 1.0f, 1.0f } -/* Aquamarine color { R:127, G:255, B:212, A:255 } */ -#define SG_AQUAMARINE { 0.498039216f, 1.0f, 0.831372549f, 1.0f } -/* Azure color { R:240, G:255, B:255, A:255 } */ -#define SG_AZURE { 0.941176471f, 1.0f, 1.0f, 1.0f } -/* Beige color { R:245, G:245, B:220, A:255 } */ -#define SG_BEIGE { 0.960784314f, 0.960784314f, 0.862745098f, 1.0f } -/* Bisque color { R:255, G:228, B:196, A:255 } */ -#define SG_BISQUE { 1.0f, 0.894117647f, 0.768627451f, 1.0f } -/* Black color { R:0, G:0, B:0, A:255 } */ -#define SG_BLACK { 0.0f, 0.0f, 0.0f, 1.0f } -/* Blanched Almond color { R:255, G:235, B:205, A:255 } */ -#define SG_BLANCHED_ALMOND { 1.0f, 0.921568627f, 0.803921569f, 1.0f } -/* Blue color { R:0, G:0, B:255, A:255 } */ -#define SG_BLUE { 0.0f, 0.0f, 1.0f, 1.0f } -/* Blue Violet color { R:138, G:43, B:226, A:255 } */ -#define SG_BLUE_VIOLET { 0.541176471f, 0.168627451f, 0.88627451f, 1.0f } -/* Brown color { R:165, G:42, B:42, A:255 } */ -#define SG_BROWN { 0.647058824f, 0.164705882f, 0.164705882f, 1.0f } -/* Burlywood color { R:222, G:184, B:135, A:255 } */ -#define SG_BURLYWOOD { 0.870588235f, 0.721568627f, 0.529411765f, 1.0f } -/* Cadet Blue color { R:95, G:158, B:160, A:255 } */ -#define SG_CADET_BLUE { 0.37254902f, 0.619607843f, 0.62745098f, 1.0f } -/* Chartreuse color { R:127, G:255, B:0, A:255 } */ -#define SG_CHARTREUSE { 0.498039216f, 1.0f, 0.0f, 1.0f } -/* Chocolate color { R:210, G:105, B:30, A:255 } */ -#define SG_CHOCOLATE { 0.823529412f, 0.411764706f, 0.117647059f, 1.0f } -/* Coral color { R:255, G:127, B:80, A:255 } */ -#define SG_CORAL { 1.0f, 0.498039216f, 0.31372549f, 1.0f } -/* Cornflower Blue color { R:100, G:149, B:237, A:255 } */ -#define SG_CORNFLOWER_BLUE { 0.392156863f, 0.584313725f, 0.929411765f, 1.0f } -/* Cornsilk color { R:255, G:248, B:220, A:255 } */ -#define SG_CORNSILK { 1.0f, 0.97254902f, 0.862745098f, 1.0f } -/* Crimson color { R:220, G:20, B:60, A:255 } */ -#define SG_CRIMSON { 0.862745098f, 0.0784313725f, 0.235294118f, 1.0f } -/* Cyan color { R:0, G:255, B:255, A:255 } */ -#define SG_CYAN { 0.0f, 1.0f, 1.0f, 1.0f } -/* Dark Blue color { R:0, G:0, B:139, A:255 } */ -#define SG_DARK_BLUE { 0.0f, 0.0f, 0.545098039f, 1.0f } -/* Dark Cyan color { R:0, G:139, B:139, A:255 } */ -#define SG_DARK_CYAN { 0.0f, 0.545098039f, 0.545098039f, 1.0f } -/* Dark Goldenrod color { R:184, G:134, B:11, A:255 } */ -#define SG_DARK_GOLDENROD { 0.721568627f, 0.525490196f, 0.0431372549f, 1.0f } -/* Dark Gray color { R:169, G:169, B:169, A:255 } */ -#define SG_DARK_GRAY { 0.662745098f, 0.662745098f, 0.662745098f, 1.0f } -/* Dark Green color { R:0, G:100, B:0, A:255 } */ -#define SG_DARK_GREEN { 0.0f, 0.392156863f, 0.0f, 1.0f } -/* Dark Khaki color { R:189, G:183, B:107, A:255 } */ -#define SG_DARK_KHAKI { 0.741176471f, 0.717647059f, 0.419607843f, 1.0f } -/* Dark Magenta color { R:139, G:0, B:139, A:255 } */ -#define SG_DARK_MAGENTA { 0.545098039f, 0.0f, 0.545098039f, 1.0f } -/* Dark Olive Green color { R:85, G:107, B:47, A:255 } */ -#define SG_DARK_OLIVE_GREEN { 0.333333333f, 0.419607843f, 0.184313725f, 1.0f } -/* Dark Orange color { R:255, G:140, B:0, A:255 } */ -#define SG_DARK_ORANGE { 1.0f, 0.549019608f, 0.0f, 1.0f } -/* Dark Orchid color { R:153, G:50, B:204, A:255 } */ -#define SG_DARK_ORCHID { 0.6f, 0.196078431f, 0.8f, 1.0f } -/* Dark Red color { R:139, G:0, B:0, A:255 } */ -#define SG_DARK_RED { 0.545098039f, 0.0f, 0.0f, 1.0f } -/* Dark Salmon color { R:233, G:150, B:122, A:255 } */ -#define SG_DARK_SALMON { 0.91372549f, 0.588235294f, 0.478431373f, 1.0f } -/* Dark Sea Green color { R:143, G:188, B:143, A:255 } */ -#define SG_DARK_SEA_GREEN { 0.560784314f, 0.737254902f, 0.560784314f, 1.0f } -/* Dark Slate Blue color { R:72, G:61, B:139, A:255 } */ -#define SG_DARK_SLATE_BLUE { 0.282352941f, 0.239215686f, 0.545098039f, 1.0f } -/* Dark Slate Gray color { R:47, G:79, B:79, A:255 } */ -#define SG_DARK_SLATE_GRAY { 0.184313725f, 0.309803922f, 0.309803922f, 1.0f } -/* Dark Turquoise color { R:0, G:206, B:209, A:255 } */ -#define SG_DARK_TURQUOISE { 0.0f, 0.807843137f, 0.819607843f, 1.0f } -/* Dark Violet color { R:148, G:0, B:211, A:255 } */ -#define SG_DARK_VIOLET { 0.580392157f, 0.0f, 0.82745098f, 1.0f } -/* Deep Pink color { R:255, G:20, B:147, A:255 } */ -#define SG_DEEP_PINK { 1.0f, 0.0784313725f, 0.576470588f, 1.0f } -/* Deep Sky Blue color { R:0, G:191, B:255, A:255 } */ -#define SG_DEEP_SKY_BLUE { 0.0f, 0.749019608f, 1.0f, 1.0f } -/* Dim Gray color { R:105, G:105, B:105, A:255 } */ -#define SG_DIM_GRAY { 0.411764706f, 0.411764706f, 0.411764706f, 1.0f } -/* Dodger Blue color { R:30, G:144, B:255, A:255 } */ -#define SG_DODGER_BLUE { 0.117647059f, 0.564705882f, 1.0f, 1.0f } -/* Firebrick color { R:178, G:34, B:34, A:255 } */ -#define SG_FIREBRICK { 0.698039216f, 0.133333333f, 0.133333333f, 1.0f } -/* Floral White color { R:255, G:250, B:240, A:255 } */ -#define SG_FLORAL_WHITE { 1.0f, 0.980392157f, 0.941176471f, 1.0f } -/* Forest Green color { R:34, G:139, B:34, A:255 } */ -#define SG_FOREST_GREEN { 0.133333333f, 0.545098039f, 0.133333333f, 1.0f } -/* Fuchsia color { R:255, G:0, B:255, A:255 } */ -#define SG_FUCHSIA { 1.0f, 0.0f, 1.0f, 1.0f } -/* Gainsboro color { R:220, G:220, B:220, A:255 } */ -#define SG_GAINSBORO { 0.862745098f, 0.862745098f, 0.862745098f, 1.0f } -/* Ghost White color { R:248, G:248, B:255, A:255 } */ -#define SG_GHOST_WHITE { 0.97254902f, 0.97254902f, 1.0f, 1.0f } -/* Gold color { R:255, G:215, B:0, A:255 } */ -#define SG_GOLD { 1.0f, 0.843137255f, 0.0f, 1.0f } -/* Goldenrod color { R:218, G:165, B:32, A:255 } */ -#define SG_GOLDENROD { 0.854901961f, 0.647058824f, 0.125490196f, 1.0f } -/* Gray color { R:190, G:190, B:190, A:255 } */ -#define SG_GRAY { 0.745098039f, 0.745098039f, 0.745098039f, 1.0f } -/* Web Gray color { R:128, G:128, B:128, A:255 } */ -#define SG_WEB_GRAY { 0.501960784f, 0.501960784f, 0.501960784f, 1.0f } -/* Green color { R:0, G:255, B:0, A:255 } */ -#define SG_GREEN { 0.0f, 1.0f, 0.0f, 1.0f } -/* Web Green color { R:0, G:128, B:0, A:255 } */ -#define SG_WEB_GREEN { 0.0f, 0.501960784f, 0.0f, 1.0f } -/* Green Yellow color { R:173, G:255, B:47, A:255 } */ -#define SG_GREEN_YELLOW { 0.678431373f, 1.0f, 0.184313725f, 1.0f } -/* Honeydew color { R:240, G:255, B:240, A:255 } */ -#define SG_HONEYDEW { 0.941176471f, 1.0f, 0.941176471f, 1.0f } -/* Hot Pink color { R:255, G:105, B:180, A:255 } */ -#define SG_HOT_PINK { 1.0f, 0.411764706f, 0.705882353f, 1.0f } -/* Indian Red color { R:205, G:92, B:92, A:255 } */ -#define SG_INDIAN_RED { 0.803921569f, 0.360784314f, 0.360784314f, 1.0f } -/* Indigo color { R:75, G:0, B:130, A:255 } */ -#define SG_INDIGO { 0.294117647f, 0.0f, 0.509803922f, 1.0f } -/* Ivory color { R:255, G:255, B:240, A:255 } */ -#define SG_IVORY { 1.0f, 1.0f, 0.941176471f, 1.0f } -/* Khaki color { R:240, G:230, B:140, A:255 } */ -#define SG_KHAKI { 0.941176471f, 0.901960784f, 0.549019608f, 1.0f } -/* Lavender color { R:230, G:230, B:250, A:255 } */ -#define SG_LAVENDER { 0.901960784f, 0.901960784f, 0.980392157f, 1.0f } -/* Lavender Blush color { R:255, G:240, B:245, A:255 } */ -#define SG_LAVENDER_BLUSH { 1.0f, 0.941176471f, 0.960784314f, 1.0f } -/* Lawn Green color { R:124, G:252, B:0, A:255 } */ -#define SG_LAWN_GREEN { 0.48627451f, 0.988235294f, 0.0f, 1.0f } -/* Lemon Chiffon color { R:255, G:250, B:205, A:255 } */ -#define SG_LEMON_CHIFFON { 1.0f, 0.980392157f, 0.803921569f, 1.0f } -/* Light Blue color { R:173, G:216, B:230, A:255 } */ -#define SG_LIGHT_BLUE { 0.678431373f, 0.847058824f, 0.901960784f, 1.0f } -/* Light Coral color { R:240, G:128, B:128, A:255 } */ -#define SG_LIGHT_CORAL { 0.941176471f, 0.501960784f, 0.501960784f, 1.0f } -/* Light Cyan color { R:224, G:255, B:255, A:255 } */ -#define SG_LIGHT_CYAN { 0.878431373f, 1.0f, 1.0f, 1.0f } -/* Light Goldenrod color { R:250, G:250, B:210, A:255 } */ -#define SG_LIGHT_GOLDENROD { 0.980392157f, 0.980392157f, 0.823529412f, 1.0f } -/* Light Gray color { R:211, G:211, B:211, A:255 } */ -#define SG_LIGHT_GRAY { 0.82745098f, 0.82745098f, 0.82745098f, 1.0f } -/* Light Green color { R:144, G:238, B:144, A:255 } */ -#define SG_LIGHT_GREEN { 0.564705882f, 0.933333333f, 0.564705882f, 1.0f } -/* Light Pink color { R:255, G:182, B:193, A:255 } */ -#define SG_LIGHT_PINK { 1.0f, 0.71372549f, 0.756862745f, 1.0f } -/* Light Salmon color { R:255, G:160, B:122, A:255 } */ -#define SG_LIGHT_SALMON { 1.0f, 0.62745098f, 0.478431373f, 1.0f } -/* Light Sea Green color { R:32, G:178, B:170, A:255 } */ -#define SG_LIGHT_SEA_GREEN { 0.125490196f, 0.698039216f, 0.666666667f, 1.0f } -/* Light Sky Blue color { R:135, G:206, B:250, A:255 } */ -#define SG_LIGHT_SKY_BLUE { 0.529411765f, 0.807843137f, 0.980392157f, 1.0f } -/* Light Slate Gray color { R:119, G:136, B:153, A:255 } */ -#define SG_LIGHT_SLATE_GRAY { 0.466666667f, 0.533333333f, 0.6f, 1.0f } -/* Light Steel Blue color { R:176, G:196, B:222, A:255 } */ -#define SG_LIGHT_STEEL_BLUE { 0.690196078f, 0.768627451f, 0.870588235f, 1.0f } -/* Light Yellow color { R:255, G:255, B:224, A:255 } */ -#define SG_LIGHT_YELLOW { 1.0f, 1.0f, 0.878431373f, 1.0f } -/* Lime color { R:0, G:255, B:0, A:255 } */ -#define SG_LIME { 0.0f, 1.0f, 0.0f, 1.0f } -/* Lime Green color { R:50, G:205, B:50, A:255 } */ -#define SG_LIME_GREEN { 0.196078431f, 0.803921569f, 0.196078431f, 1.0f } -/* Linen color { R:250, G:240, B:230, A:255 } */ -#define SG_LINEN { 0.980392157f, 0.941176471f, 0.901960784f, 1.0f } -/* Magenta color { R:255, G:0, B:255, A:255 } */ -#define SG_MAGENTA { 1.0f, 0.0f, 1.0f, 1.0f } -/* Maroon color { R:176, G:48, B:96, A:255 } */ -#define SG_MAROON { 0.690196078f, 0.188235294f, 0.376470588f, 1.0f } -/* Web Maroon color { R:128, G:0, B:0, A:255 } */ -#define SG_WEB_MAROON { 0.501960784f, 0.0f, 0.0f, 1.0f } -/* Medium Aquamarine color { R:102, G:205, B:170, A:255 } */ -#define SG_MEDIUM_AQUAMARINE { 0.4f, 0.803921569f, 0.666666667f, 1.0f } -/* Medium Blue color { R:0, G:0, B:205, A:255 } */ -#define SG_MEDIUM_BLUE { 0.0f, 0.0f, 0.803921569f, 1.0f } -/* Medium Orchid color { R:186, G:85, B:211, A:255 } */ -#define SG_MEDIUM_ORCHID { 0.729411765f, 0.333333333f, 0.82745098f, 1.0f } -/* Medium Purple color { R:147, G:112, B:219, A:255 } */ -#define SG_MEDIUM_PURPLE { 0.576470588f, 0.439215686f, 0.858823529f, 1.0f } -/* Medium Sea Green color { R:60, G:179, B:113, A:255 } */ -#define SG_MEDIUM_SEA_GREEN { 0.235294118f, 0.701960784f, 0.443137255f, 1.0f } -/* Medium Slate Blue color { R:123, G:104, B:238, A:255 } */ -#define SG_MEDIUM_SLATE_BLUE { 0.482352941f, 0.407843137f, 0.933333333f, 1.0f } -/* Medium Spring Green color { R:0, G:250, B:154, A:255 } */ -#define SG_MEDIUM_SPRING_GREEN { 0.0f, 0.980392157f, 0.603921569f, 1.0f } -/* Medium Turquoise color { R:72, G:209, B:204, A:255 } */ -#define SG_MEDIUM_TURQUOISE { 0.282352941f, 0.819607843f, 0.8f, 1.0f } -/* Medium Violet Red color { R:199, G:21, B:133, A:255 } */ -#define SG_MEDIUM_VIOLET_RED { 0.780392157f, 0.0823529412f, 0.521568627f, 1.0f } -/* Midnight Blue color { R:25, G:25, B:112, A:255 } */ -#define SG_MIDNIGHT_BLUE { 0.0980392157f, 0.0980392157f, 0.439215686f, 1.0f } -/* Mint Cream color { R:245, G:255, B:250, A:255 } */ -#define SG_MINT_CREAM { 0.960784314f, 1.0f, 0.980392157f, 1.0f } -/* Misty Rose color { R:255, G:228, B:225, A:255 } */ -#define SG_MISTY_ROSE { 1.0f, 0.894117647f, 0.882352941f, 1.0f } -/* Moccasin color { R:255, G:228, B:181, A:255 } */ -#define SG_MOCCASIN { 1.0f, 0.894117647f, 0.709803922f, 1.0f } -/* Navajo White color { R:255, G:222, B:173, A:255 } */ -#define SG_NAVAJO_WHITE { 1.0f, 0.870588235f, 0.678431373f, 1.0f } -/* Navy Blue color { R:0, G:0, B:128, A:255 } */ -#define SG_NAVY_BLUE { 0.0f, 0.0f, 0.501960784f, 1.0f } -/* Old Lace color { R:253, G:245, B:230, A:255 } */ -#define SG_OLD_LACE { 0.992156863f, 0.960784314f, 0.901960784f, 1.0f } -/* Olive color { R:128, G:128, B:0, A:255 } */ -#define SG_OLIVE { 0.501960784f, 0.501960784f, 0.0f, 1.0f } -/* Olive Drab color { R:107, G:142, B:35, A:255 } */ -#define SG_OLIVE_DRAB { 0.419607843f, 0.556862745f, 0.137254902f, 1.0f } -/* Orange color { R:255, G:165, B:0, A:255 } */ -#define SG_ORANGE { 1.0f, 0.647058824f, 0.0f, 1.0f } -/* Orange Red color { R:255, G:69, B:0, A:255 } */ -#define SG_ORANGE_RED { 1.0f, 0.270588235f, 0.0f, 1.0f } -/* Orchid color { R:218, G:112, B:214, A:255 } */ -#define SG_ORCHID { 0.854901961f, 0.439215686f, 0.839215686f, 1.0f } -/* Pale Goldenrod color { R:238, G:232, B:170, A:255 } */ -#define SG_PALE_GOLDENROD { 0.933333333f, 0.909803922f, 0.666666667f, 1.0f } -/* Pale Green color { R:152, G:251, B:152, A:255 } */ -#define SG_PALE_GREEN { 0.596078431f, 0.984313725f, 0.596078431f, 1.0f } -/* Pale Turquoise color { R:175, G:238, B:238, A:255 } */ -#define SG_PALE_TURQUOISE { 0.68627451f, 0.933333333f, 0.933333333f, 1.0f } -/* Pale Violet Red color { R:219, G:112, B:147, A:255 } */ -#define SG_PALE_VIOLET_RED { 0.858823529f, 0.439215686f, 0.576470588f, 1.0f } -/* Papaya Whip color { R:255, G:239, B:213, A:255 } */ -#define SG_PAPAYA_WHIP { 1.0f, 0.937254902f, 0.835294118f, 1.0f } -/* Peach Puff color { R:255, G:218, B:185, A:255 } */ -#define SG_PEACH_PUFF { 1.0f, 0.854901961f, 0.725490196f, 1.0f } -/* Peru color { R:205, G:133, B:63, A:255 } */ -#define SG_PERU { 0.803921569f, 0.521568627f, 0.247058824f, 1.0f } -/* Pink color { R:255, G:192, B:203, A:255 } */ -#define SG_PINK { 1.0f, 0.752941176f, 0.796078431f, 1.0f } -/* Plum color { R:221, G:160, B:221, A:255 } */ -#define SG_PLUM { 0.866666667f, 0.62745098f, 0.866666667f, 1.0f } -/* Powder Blue color { R:176, G:224, B:230, A:255 } */ -#define SG_POWDER_BLUE { 0.690196078f, 0.878431373f, 0.901960784f, 1.0f } -/* Purple color { R:160, G:32, B:240, A:255 } */ -#define SG_PURPLE { 0.62745098f, 0.125490196f, 0.941176471f, 1.0f } -/* Web Purple color { R:128, G:0, B:128, A:255 } */ -#define SG_WEB_PURPLE { 0.501960784f, 0.0f, 0.501960784f, 1.0f } -/* Rebecca Purple color { R:102, G:51, B:153, A:255 } */ -#define SG_REBECCA_PURPLE { 0.4f, 0.2f, 0.6f, 1.0f } -/* Red color { R:255, G:0, B:0, A:255 } */ -#define SG_RED { 1.0f, 0.0f, 0.0f, 1.0f } -/* Rosy Brown color { R:188, G:143, B:143, A:255 } */ -#define SG_ROSY_BROWN { 0.737254902f, 0.560784314f, 0.560784314f, 1.0f } -/* Royal Blue color { R:65, G:105, B:225, A:255 } */ -#define SG_ROYAL_BLUE { 0.254901961f, 0.411764706f, 0.882352941f, 1.0f } -/* Saddle Brown color { R:139, G:69, B:19, A:255 } */ -#define SG_SADDLE_BROWN { 0.545098039f, 0.270588235f, 0.0745098039f, 1.0f } -/* Salmon color { R:250, G:128, B:114, A:255 } */ -#define SG_SALMON { 0.980392157f, 0.501960784f, 0.447058824f, 1.0f } -/* Sandy Brown color { R:244, G:164, B:96, A:255 } */ -#define SG_SANDY_BROWN { 0.956862745f, 0.643137255f, 0.376470588f, 1.0f } -/* Sea Green color { R:46, G:139, B:87, A:255 } */ -#define SG_SEA_GREEN { 0.180392157f, 0.545098039f, 0.341176471f, 1.0f } -/* Seashell color { R:255, G:245, B:238, A:255 } */ -#define SG_SEASHELL { 1.0f, 0.960784314f, 0.933333333f, 1.0f } -/* Sienna color { R:160, G:82, B:45, A:255 } */ -#define SG_SIENNA { 0.62745098f, 0.321568627f, 0.176470588f, 1.0f } -/* Silver color { R:192, G:192, B:192, A:255 } */ -#define SG_SILVER { 0.752941176f, 0.752941176f, 0.752941176f, 1.0f } -/* Sky Blue color { R:135, G:206, B:235, A:255 } */ -#define SG_SKY_BLUE { 0.529411765f, 0.807843137f, 0.921568627f, 1.0f } -/* Slate Blue color { R:106, G:90, B:205, A:255 } */ -#define SG_SLATE_BLUE { 0.415686275f, 0.352941176f, 0.803921569f, 1.0f } -/* Slate Gray color { R:112, G:128, B:144, A:255 } */ -#define SG_SLATE_GRAY { 0.439215686f, 0.501960784f, 0.564705882f, 1.0f } -/* Snow color { R:255, G:250, B:250, A:255 } */ -#define SG_SNOW { 1.0f, 0.980392157f, 0.980392157f, 1.0f } -/* Spring Green color { R:0, G:255, B:127, A:255 } */ -#define SG_SPRING_GREEN { 0.0f, 1.0f, 0.498039216f, 1.0f } -/* Steel Blue color { R:70, G:130, B:180, A:255 } */ -#define SG_STEEL_BLUE { 0.274509804f, 0.509803922f, 0.705882353f, 1.0f } -/* Tan color { R:210, G:180, B:140, A:255 } */ -#define SG_TAN { 0.823529412f, 0.705882353f, 0.549019608f, 1.0f } -/* Teal color { R:0, G:128, B:128, A:255 } */ -#define SG_TEAL { 0.0f, 0.501960784f, 0.501960784f, 1.0f } -/* Thistle color { R:216, G:191, B:216, A:255 } */ -#define SG_THISTLE { 0.847058824f, 0.749019608f, 0.847058824f, 1.0f } -/* Tomato color { R:255, G:99, B:71, A:255 } */ -#define SG_TOMATO { 1.0f, 0.388235294f, 0.278431373f, 1.0f } -/* Transparent color { R:0, G:0, B:0, A:0 } */ -#define SG_TRANSPARENT { 0.0f, 0.0f, 0.0f, 0.0f } -/* Turquoise color { R:64, G:224, B:208, A:255 } */ -#define SG_TURQUOISE { 0.250980392f, 0.878431373f, 0.815686275f, 1.0f } -/* Violet color { R:238, G:130, B:238, A:255 } */ -#define SG_VIOLET { 0.933333333f, 0.509803922f, 0.933333333f, 1.0f } -/* Wheat color { R:245, G:222, B:179, A:255 } */ -#define SG_WHEAT { 0.960784314f, 0.870588235f, 0.701960784f, 1.0f } -/* White color { R:255, G:255, B:255, A:255 } */ -#define SG_WHITE { 1.0f, 1.0f, 1.0f, 1.0f } -/* White Smoke color { R:245, G:245, B:245, A:255 } */ -#define SG_WHITE_SMOKE { 0.960784314f, 0.960784314f, 0.960784314f, 1.0f } -/* Yellow color { R:255, G:255, B:0, A:255 } */ -#define SG_YELLOW { 1.0f, 1.0f, 0.0f, 1.0f } -/* Yellow Green color { R:154, G:205, B:50, A:255 } */ -#define SG_YELLOW_GREEN { 0.603921569f, 0.803921569f, 0.196078431f, 1.0f } - -/* Alice Blue color { R:240, G:248, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_alice_blue = SG_ALICE_BLUE; -/* Antique White color { R:250, G:235, B:215, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_antique_white = SG_ANTIQUE_WHITE; -/* Aqua color { R:0, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_aqua = SG_AQUA; -/* Aquamarine color { R:127, G:255, B:212, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_aquamarine = SG_AQUAMARINE; -/* Azure color { R:240, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_azure = SG_AZURE; -/* Beige color { R:245, G:245, B:220, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_beige = SG_BEIGE; -/* Bisque color { R:255, G:228, B:196, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_bisque = SG_BISQUE; -/* Black color { R:0, G:0, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_black = SG_BLACK; -/* Blanched Almond color { R:255, G:235, B:205, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_blanched_almond = SG_BLANCHED_ALMOND; -/* Blue color { R:0, G:0, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_blue = SG_BLUE; -/* Blue Violet color { R:138, G:43, B:226, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_blue_violet = SG_BLUE_VIOLET; -/* Brown color { R:165, G:42, B:42, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_brown = SG_BROWN; -/* Burlywood color { R:222, G:184, B:135, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_burlywood = SG_BURLYWOOD; -/* Cadet Blue color { R:95, G:158, B:160, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_cadet_blue = SG_CADET_BLUE; -/* Chartreuse color { R:127, G:255, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_chartreuse = SG_CHARTREUSE; -/* Chocolate color { R:210, G:105, B:30, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_chocolate = SG_CHOCOLATE; -/* Coral color { R:255, G:127, B:80, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_coral = SG_CORAL; -/* Cornflower Blue color { R:100, G:149, B:237, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_cornflower_blue = SG_CORNFLOWER_BLUE; -/* Cornsilk color { R:255, G:248, B:220, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_cornsilk = SG_CORNSILK; -/* Crimson color { R:220, G:20, B:60, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_crimson = SG_CRIMSON; -/* Cyan color { R:0, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_cyan = SG_CYAN; -/* Dark Blue color { R:0, G:0, B:139, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_blue = SG_DARK_BLUE; -/* Dark Cyan color { R:0, G:139, B:139, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_cyan = SG_DARK_CYAN; -/* Dark Goldenrod color { R:184, G:134, B:11, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_goldenrod = SG_DARK_GOLDENROD; -/* Dark Gray color { R:169, G:169, B:169, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_gray = SG_DARK_GRAY; -/* Dark Green color { R:0, G:100, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_green = SG_DARK_GREEN; -/* Dark Khaki color { R:189, G:183, B:107, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_khaki = SG_DARK_KHAKI; -/* Dark Magenta color { R:139, G:0, B:139, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_magenta = SG_DARK_MAGENTA; -/* Dark Olive Green color { R:85, G:107, B:47, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_olive_green = SG_DARK_OLIVE_GREEN; -/* Dark Orange color { R:255, G:140, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_orange = SG_DARK_ORANGE; -/* Dark Orchid color { R:153, G:50, B:204, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_orchid = SG_DARK_ORCHID; -/* Dark Red color { R:139, G:0, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_red = SG_DARK_RED; -/* Dark Salmon color { R:233, G:150, B:122, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_salmon = SG_DARK_SALMON; -/* Dark Sea Green color { R:143, G:188, B:143, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_sea_green = SG_DARK_SEA_GREEN; -/* Dark Slate Blue color { R:72, G:61, B:139, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_slate_blue = SG_DARK_SLATE_BLUE; -/* Dark Slate Gray color { R:47, G:79, B:79, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_slate_gray = SG_DARK_SLATE_GRAY; -/* Dark Turquoise color { R:0, G:206, B:209, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_turquoise = SG_DARK_TURQUOISE; -/* Dark Violet color { R:148, G:0, B:211, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dark_violet = SG_DARK_VIOLET; -/* Deep Pink color { R:255, G:20, B:147, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_deep_pink = SG_DEEP_PINK; -/* Deep Sky Blue color { R:0, G:191, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_deep_sky_blue = SG_DEEP_SKY_BLUE; -/* Dim Gray color { R:105, G:105, B:105, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dim_gray = SG_DIM_GRAY; -/* Dodger Blue color { R:30, G:144, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_dodger_blue = SG_DODGER_BLUE; -/* Firebrick color { R:178, G:34, B:34, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_firebrick = SG_FIREBRICK; -/* Floral White color { R:255, G:250, B:240, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_floral_white = SG_FLORAL_WHITE; -/* Forest Green color { R:34, G:139, B:34, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_forest_green = SG_FOREST_GREEN; -/* Fuchsia color { R:255, G:0, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_fuchsia = SG_FUCHSIA; -/* Gainsboro color { R:220, G:220, B:220, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_gainsboro = SG_GAINSBORO; -/* Ghost White color { R:248, G:248, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_ghost_white = SG_GHOST_WHITE; -/* Gold color { R:255, G:215, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_gold = SG_GOLD; -/* Goldenrod color { R:218, G:165, B:32, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_goldenrod = SG_GOLDENROD; -/* Gray color { R:190, G:190, B:190, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_gray = SG_GRAY; -/* Web Gray color { R:128, G:128, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_web_gray = SG_WEB_GRAY; -/* Green color { R:0, G:255, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_green = SG_GREEN; -/* Web Green color { R:0, G:128, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_web_green = SG_WEB_GREEN; -/* Green Yellow color { R:173, G:255, B:47, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_green_yellow = SG_GREEN_YELLOW; -/* Honeydew color { R:240, G:255, B:240, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_honeydew = SG_HONEYDEW; -/* Hot Pink color { R:255, G:105, B:180, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_hot_pink = SG_HOT_PINK; -/* Indian Red color { R:205, G:92, B:92, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_indian_red = SG_INDIAN_RED; -/* Indigo color { R:75, G:0, B:130, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_indigo = SG_INDIGO; -/* Ivory color { R:255, G:255, B:240, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_ivory = SG_IVORY; -/* Khaki color { R:240, G:230, B:140, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_khaki = SG_KHAKI; -/* Lavender color { R:230, G:230, B:250, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lavender = SG_LAVENDER; -/* Lavender Blush color { R:255, G:240, B:245, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lavender_blush = SG_LAVENDER_BLUSH; -/* Lawn Green color { R:124, G:252, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lawn_green = SG_LAWN_GREEN; -/* Lemon Chiffon color { R:255, G:250, B:205, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lemon_chiffon = SG_LEMON_CHIFFON; -/* Light Blue color { R:173, G:216, B:230, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_blue = SG_LIGHT_BLUE; -/* Light Coral color { R:240, G:128, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_coral = SG_LIGHT_CORAL; -/* Light Cyan color { R:224, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_cyan = SG_LIGHT_CYAN; -/* Light Goldenrod color { R:250, G:250, B:210, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_goldenrod = SG_LIGHT_GOLDENROD; -/* Light Gray color { R:211, G:211, B:211, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_gray = SG_LIGHT_GRAY; -/* Light Green color { R:144, G:238, B:144, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_green = SG_LIGHT_GREEN; -/* Light Pink color { R:255, G:182, B:193, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_pink = SG_LIGHT_PINK; -/* Light Salmon color { R:255, G:160, B:122, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_salmon = SG_LIGHT_SALMON; -/* Light Sea Green color { R:32, G:178, B:170, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_sea_green = SG_LIGHT_SEA_GREEN; -/* Light Sky Blue color { R:135, G:206, B:250, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_sky_blue = SG_LIGHT_SKY_BLUE; -/* Light Slate Gray color { R:119, G:136, B:153, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_slate_gray = SG_LIGHT_SLATE_GRAY; -/* Light Steel Blue color { R:176, G:196, B:222, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_steel_blue = SG_LIGHT_STEEL_BLUE; -/* Light Yellow color { R:255, G:255, B:224, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_light_yellow = SG_LIGHT_YELLOW; -/* Lime color { R:0, G:255, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lime = SG_LIME; -/* Lime Green color { R:50, G:205, B:50, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_lime_green = SG_LIME_GREEN; -/* Linen color { R:250, G:240, B:230, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_linen = SG_LINEN; -/* Magenta color { R:255, G:0, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_magenta = SG_MAGENTA; -/* Maroon color { R:176, G:48, B:96, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_maroon = SG_MAROON; -/* Web Maroon color { R:128, G:0, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_web_maroon = SG_WEB_MAROON; -/* Medium Aquamarine color { R:102, G:205, B:170, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_aquamarine = SG_MEDIUM_AQUAMARINE; -/* Medium Blue color { R:0, G:0, B:205, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_blue = SG_MEDIUM_BLUE; -/* Medium Orchid color { R:186, G:85, B:211, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_orchid = SG_MEDIUM_ORCHID; -/* Medium Purple color { R:147, G:112, B:219, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_purple = SG_MEDIUM_PURPLE; -/* Medium Sea Green color { R:60, G:179, B:113, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_sea_green = SG_MEDIUM_SEA_GREEN; -/* Medium Slate Blue color { R:123, G:104, B:238, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_slate_blue = SG_MEDIUM_SLATE_BLUE; -/* Medium Spring Green color { R:0, G:250, B:154, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_spring_green = SG_MEDIUM_SPRING_GREEN; -/* Medium Turquoise color { R:72, G:209, B:204, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_turquoise = SG_MEDIUM_TURQUOISE; -/* Medium Violet Red color { R:199, G:21, B:133, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_medium_violet_red = SG_MEDIUM_VIOLET_RED; -/* Midnight Blue color { R:25, G:25, B:112, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_midnight_blue = SG_MIDNIGHT_BLUE; -/* Mint Cream color { R:245, G:255, B:250, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_mint_cream = SG_MINT_CREAM; -/* Misty Rose color { R:255, G:228, B:225, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_misty_rose = SG_MISTY_ROSE; -/* Moccasin color { R:255, G:228, B:181, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_moccasin = SG_MOCCASIN; -/* Navajo White color { R:255, G:222, B:173, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_navajo_white = SG_NAVAJO_WHITE; -/* Navy Blue color { R:0, G:0, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_navy_blue = SG_NAVY_BLUE; -/* Old Lace color { R:253, G:245, B:230, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_old_lace = SG_OLD_LACE; -/* Olive color { R:128, G:128, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_olive = SG_OLIVE; -/* Olive Drab color { R:107, G:142, B:35, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_olive_drab = SG_OLIVE_DRAB; -/* Orange color { R:255, G:165, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_orange = SG_ORANGE; -/* Orange Red color { R:255, G:69, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_orange_red = SG_ORANGE_RED; -/* Orchid color { R:218, G:112, B:214, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_orchid = SG_ORCHID; -/* Pale Goldenrod color { R:238, G:232, B:170, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pale_goldenrod = SG_PALE_GOLDENROD; -/* Pale Green color { R:152, G:251, B:152, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pale_green = SG_PALE_GREEN; -/* Pale Turquoise color { R:175, G:238, B:238, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pale_turquoise = SG_PALE_TURQUOISE; -/* Pale Violet Red color { R:219, G:112, B:147, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pale_violet_red = SG_PALE_VIOLET_RED; -/* Papaya Whip color { R:255, G:239, B:213, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_papaya_whip = SG_PAPAYA_WHIP; -/* Peach Puff color { R:255, G:218, B:185, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_peach_puff = SG_PEACH_PUFF; -/* Peru color { R:205, G:133, B:63, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_peru = SG_PERU; -/* Pink color { R:255, G:192, B:203, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_pink = SG_PINK; -/* Plum color { R:221, G:160, B:221, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_plum = SG_PLUM; -/* Powder Blue color { R:176, G:224, B:230, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_powder_blue = SG_POWDER_BLUE; -/* Purple color { R:160, G:32, B:240, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_purple = SG_PURPLE; -/* Web Purple color { R:128, G:0, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_web_purple = SG_WEB_PURPLE; -/* Rebecca Purple color { R:102, G:51, B:153, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_rebecca_purple = SG_REBECCA_PURPLE; -/* Red color { R:255, G:0, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_red = SG_RED; -/* Rosy Brown color { R:188, G:143, B:143, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_rosy_brown = SG_ROSY_BROWN; -/* Royal Blue color { R:65, G:105, B:225, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_royal_blue = SG_ROYAL_BLUE; -/* Saddle Brown color { R:139, G:69, B:19, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_saddle_brown = SG_SADDLE_BROWN; -/* Salmon color { R:250, G:128, B:114, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_salmon = SG_SALMON; -/* Sandy Brown color { R:244, G:164, B:96, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_sandy_brown = SG_SANDY_BROWN; -/* Sea Green color { R:46, G:139, B:87, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_sea_green = SG_SEA_GREEN; -/* Seashell color { R:255, G:245, B:238, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_seashell = SG_SEASHELL; -/* Sienna color { R:160, G:82, B:45, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_sienna = SG_SIENNA; -/* Silver color { R:192, G:192, B:192, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_silver = SG_SILVER; -/* Sky Blue color { R:135, G:206, B:235, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_sky_blue = SG_SKY_BLUE; -/* Slate Blue color { R:106, G:90, B:205, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_slate_blue = SG_SLATE_BLUE; -/* Slate Gray color { R:112, G:128, B:144, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_slate_gray = SG_SLATE_GRAY; -/* Snow color { R:255, G:250, B:250, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_snow = SG_SNOW; -/* Spring Green color { R:0, G:255, B:127, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_spring_green = SG_SPRING_GREEN; -/* Steel Blue color { R:70, G:130, B:180, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_steel_blue = SG_STEEL_BLUE; -/* Tan color { R:210, G:180, B:140, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_tan = SG_TAN; -/* Teal color { R:0, G:128, B:128, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_teal = SG_TEAL; -/* Thistle color { R:216, G:191, B:216, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_thistle = SG_THISTLE; -/* Tomato color { R:255, G:99, B:71, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_tomato = SG_TOMATO; -/* Transparent color { R:0, G:0, B:0, A:0 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_transparent = SG_TRANSPARENT; -/* Turquoise color { R:64, G:224, B:208, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_turquoise = SG_TURQUOISE; -/* Violet color { R:238, G:130, B:238, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_violet = SG_VIOLET; -/* Wheat color { R:245, G:222, B:179, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_wheat = SG_WHEAT; -/* White color { R:255, G:255, B:255, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_white = SG_WHITE; -/* White Smoke color { R:245, G:245, B:245, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_white_smoke = SG_WHITE_SMOKE; -/* Yellow color { R:255, G:255, B:0, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_yellow = SG_YELLOW; -/* Yellow Green color { R:154, G:205, B:50, A:255 } */ -static SOKOL_COLOR_CONSTEXPR sg_color sg_yellow_green = SG_YELLOW_GREEN; - -/* Alice Blue color { R:240, G:248, B:255, A:255 } */ -#define SG_ALICE_BLUE_RGBA32 0xF0F8FFFF -/* Antique White color { R:250, G:235, B:215, A:255 } */ -#define SG_ANTIQUE_WHITE_RGBA32 0xFAEBD7FF -/* Aqua color { R:0, G:255, B:255, A:255 } */ -#define SG_AQUA_RGBA32 0x00FFFFFF -/* Aquamarine color { R:127, G:255, B:212, A:255 } */ -#define SG_AQUAMARINE_RGBA32 0x7FFFD4FF -/* Azure color { R:240, G:255, B:255, A:255 } */ -#define SG_AZURE_RGBA32 0xF0FFFFFF -/* Beige color { R:245, G:245, B:220, A:255 } */ -#define SG_BEIGE_RGBA32 0xF5F5DCFF -/* Bisque color { R:255, G:228, B:196, A:255 } */ -#define SG_BISQUE_RGBA32 0xFFE4C4FF -/* Black color { R:0, G:0, B:0, A:255 } */ -#define SG_BLACK_RGBA32 0x000000FF -/* Blanched Almond color { R:255, G:235, B:205, A:255 } */ -#define SG_BLANCHED_ALMOND_RGBA32 0xFFEBCDFF -/* Blue color { R:0, G:0, B:255, A:255 } */ -#define SG_BLUE_RGBA32 0x0000FFFF -/* Blue Violet color { R:138, G:43, B:226, A:255 } */ -#define SG_BLUE_VIOLET_RGBA32 0x8A2BE2FF -/* Brown color { R:165, G:42, B:42, A:255 } */ -#define SG_BROWN_RGBA32 0xA52A2AFF -/* Burlywood color { R:222, G:184, B:135, A:255 } */ -#define SG_BURLYWOOD_RGBA32 0xDEB887FF -/* Cadet Blue color { R:95, G:158, B:160, A:255 } */ -#define SG_CADET_BLUE_RGBA32 0x5F9EA0FF -/* Chartreuse color { R:127, G:255, B:0, A:255 } */ -#define SG_CHARTREUSE_RGBA32 0x7FFF00FF -/* Chocolate color { R:210, G:105, B:30, A:255 } */ -#define SG_CHOCOLATE_RGBA32 0xD2691EFF -/* Coral color { R:255, G:127, B:80, A:255 } */ -#define SG_CORAL_RGBA32 0xFF7F50FF -/* Cornflower Blue color { R:100, G:149, B:237, A:255 } */ -#define SG_CORNFLOWER_BLUE_RGBA32 0x6495EDFF -/* Cornsilk color { R:255, G:248, B:220, A:255 } */ -#define SG_CORNSILK_RGBA32 0xFFF8DCFF -/* Crimson color { R:220, G:20, B:60, A:255 } */ -#define SG_CRIMSON_RGBA32 0xDC143CFF -/* Cyan color { R:0, G:255, B:255, A:255 } */ -#define SG_CYAN_RGBA32 0x00FFFFFF -/* Dark Blue color { R:0, G:0, B:139, A:255 } */ -#define SG_DARK_BLUE_RGBA32 0x00008BFF -/* Dark Cyan color { R:0, G:139, B:139, A:255 } */ -#define SG_DARK_CYAN_RGBA32 0x008B8BFF -/* Dark Goldenrod color { R:184, G:134, B:11, A:255 } */ -#define SG_DARK_GOLDENROD_RGBA32 0xB8860BFF -/* Dark Gray color { R:169, G:169, B:169, A:255 } */ -#define SG_DARK_GRAY_RGBA32 0xA9A9A9FF -/* Dark Green color { R:0, G:100, B:0, A:255 } */ -#define SG_DARK_GREEN_RGBA32 0x006400FF -/* Dark Khaki color { R:189, G:183, B:107, A:255 } */ -#define SG_DARK_KHAKI_RGBA32 0xBDB76BFF -/* Dark Magenta color { R:139, G:0, B:139, A:255 } */ -#define SG_DARK_MAGENTA_RGBA32 0x8B008BFF -/* Dark Olive Green color { R:85, G:107, B:47, A:255 } */ -#define SG_DARK_OLIVE_GREEN_RGBA32 0x556B2FFF -/* Dark Orange color { R:255, G:140, B:0, A:255 } */ -#define SG_DARK_ORANGE_RGBA32 0xFF8C00FF -/* Dark Orchid color { R:153, G:50, B:204, A:255 } */ -#define SG_DARK_ORCHID_RGBA32 0x9932CCFF -/* Dark Red color { R:139, G:0, B:0, A:255 } */ -#define SG_DARK_RED_RGBA32 0x8B0000FF -/* Dark Salmon color { R:233, G:150, B:122, A:255 } */ -#define SG_DARK_SALMON_RGBA32 0xE9967AFF -/* Dark Sea Green color { R:143, G:188, B:143, A:255 } */ -#define SG_DARK_SEA_GREEN_RGBA32 0x8FBC8FFF -/* Dark Slate Blue color { R:72, G:61, B:139, A:255 } */ -#define SG_DARK_SLATE_BLUE_RGBA32 0x483D8BFF -/* Dark Slate Gray color { R:47, G:79, B:79, A:255 } */ -#define SG_DARK_SLATE_GRAY_RGBA32 0x2F4F4FFF -/* Dark Turquoise color { R:0, G:206, B:209, A:255 } */ -#define SG_DARK_TURQUOISE_RGBA32 0x00CED1FF -/* Dark Violet color { R:148, G:0, B:211, A:255 } */ -#define SG_DARK_VIOLET_RGBA32 0x9400D3FF -/* Deep Pink color { R:255, G:20, B:147, A:255 } */ -#define SG_DEEP_PINK_RGBA32 0xFF1493FF -/* Deep Sky Blue color { R:0, G:191, B:255, A:255 } */ -#define SG_DEEP_SKY_BLUE_RGBA32 0x00BFFFFF -/* Dim Gray color { R:105, G:105, B:105, A:255 } */ -#define SG_DIM_GRAY_RGBA32 0x696969FF -/* Dodger Blue color { R:30, G:144, B:255, A:255 } */ -#define SG_DODGER_BLUE_RGBA32 0x1E90FFFF -/* Firebrick color { R:178, G:34, B:34, A:255 } */ -#define SG_FIREBRICK_RGBA32 0xB22222FF -/* Floral White color { R:255, G:250, B:240, A:255 } */ -#define SG_FLORAL_WHITE_RGBA32 0xFFFAF0FF -/* Forest Green color { R:34, G:139, B:34, A:255 } */ -#define SG_FOREST_GREEN_RGBA32 0x228B22FF -/* Fuchsia color { R:255, G:0, B:255, A:255 } */ -#define SG_FUCHSIA_RGBA32 0xFF00FFFF -/* Gainsboro color { R:220, G:220, B:220, A:255 } */ -#define SG_GAINSBORO_RGBA32 0xDCDCDCFF -/* Ghost White color { R:248, G:248, B:255, A:255 } */ -#define SG_GHOST_WHITE_RGBA32 0xF8F8FFFF -/* Gold color { R:255, G:215, B:0, A:255 } */ -#define SG_GOLD_RGBA32 0xFFD700FF -/* Goldenrod color { R:218, G:165, B:32, A:255 } */ -#define SG_GOLDENROD_RGBA32 0xDAA520FF -/* Gray color { R:190, G:190, B:190, A:255 } */ -#define SG_GRAY_RGBA32 0xBEBEBEFF -/* Web Gray color { R:128, G:128, B:128, A:255 } */ -#define SG_WEB_GRAY_RGBA32 0x808080FF -/* Green color { R:0, G:255, B:0, A:255 } */ -#define SG_GREEN_RGBA32 0x00FF00FF -/* Web Green color { R:0, G:128, B:0, A:255 } */ -#define SG_WEB_GREEN_RGBA32 0x008000FF -/* Green Yellow color { R:173, G:255, B:47, A:255 } */ -#define SG_GREEN_YELLOW_RGBA32 0xADFF2FFF -/* Honeydew color { R:240, G:255, B:240, A:255 } */ -#define SG_HONEYDEW_RGBA32 0xF0FFF0FF -/* Hot Pink color { R:255, G:105, B:180, A:255 } */ -#define SG_HOT_PINK_RGBA32 0xFF69B4FF -/* Indian Red color { R:205, G:92, B:92, A:255 } */ -#define SG_INDIAN_RED_RGBA32 0xCD5C5CFF -/* Indigo color { R:75, G:0, B:130, A:255 } */ -#define SG_INDIGO_RGBA32 0x4B0082FF -/* Ivory color { R:255, G:255, B:240, A:255 } */ -#define SG_IVORY_RGBA32 0xFFFFF0FF -/* Khaki color { R:240, G:230, B:140, A:255 } */ -#define SG_KHAKI_RGBA32 0xF0E68CFF -/* Lavender color { R:230, G:230, B:250, A:255 } */ -#define SG_LAVENDER_RGBA32 0xE6E6FAFF -/* Lavender Blush color { R:255, G:240, B:245, A:255 } */ -#define SG_LAVENDER_BLUSH_RGBA32 0xFFF0F5FF -/* Lawn Green color { R:124, G:252, B:0, A:255 } */ -#define SG_LAWN_GREEN_RGBA32 0x7CFC00FF -/* Lemon Chiffon color { R:255, G:250, B:205, A:255 } */ -#define SG_LEMON_CHIFFON_RGBA32 0xFFFACDFF -/* Light Blue color { R:173, G:216, B:230, A:255 } */ -#define SG_LIGHT_BLUE_RGBA32 0xADD8E6FF -/* Light Coral color { R:240, G:128, B:128, A:255 } */ -#define SG_LIGHT_CORAL_RGBA32 0xF08080FF -/* Light Cyan color { R:224, G:255, B:255, A:255 } */ -#define SG_LIGHT_CYAN_RGBA32 0xE0FFFFFF -/* Light Goldenrod color { R:250, G:250, B:210, A:255 } */ -#define SG_LIGHT_GOLDENROD_RGBA32 0xFAFAD2FF -/* Light Gray color { R:211, G:211, B:211, A:255 } */ -#define SG_LIGHT_GRAY_RGBA32 0xD3D3D3FF -/* Light Green color { R:144, G:238, B:144, A:255 } */ -#define SG_LIGHT_GREEN_RGBA32 0x90EE90FF -/* Light Pink color { R:255, G:182, B:193, A:255 } */ -#define SG_LIGHT_PINK_RGBA32 0xFFB6C1FF -/* Light Salmon color { R:255, G:160, B:122, A:255 } */ -#define SG_LIGHT_SALMON_RGBA32 0xFFA07AFF -/* Light Sea Green color { R:32, G:178, B:170, A:255 } */ -#define SG_LIGHT_SEA_GREEN_RGBA32 0x20B2AAFF -/* Light Sky Blue color { R:135, G:206, B:250, A:255 } */ -#define SG_LIGHT_SKY_BLUE_RGBA32 0x87CEFAFF -/* Light Slate Gray color { R:119, G:136, B:153, A:255 } */ -#define SG_LIGHT_SLATE_GRAY_RGBA32 0x778899FF -/* Light Steel Blue color { R:176, G:196, B:222, A:255 } */ -#define SG_LIGHT_STEEL_BLUE_RGBA32 0xB0C4DEFF -/* Light Yellow color { R:255, G:255, B:224, A:255 } */ -#define SG_LIGHT_YELLOW_RGBA32 0xFFFFE0FF -/* Lime color { R:0, G:255, B:0, A:255 } */ -#define SG_LIME_RGBA32 0x00FF00FF -/* Lime Green color { R:50, G:205, B:50, A:255 } */ -#define SG_LIME_GREEN_RGBA32 0x32CD32FF -/* Linen color { R:250, G:240, B:230, A:255 } */ -#define SG_LINEN_RGBA32 0xFAF0E6FF -/* Magenta color { R:255, G:0, B:255, A:255 } */ -#define SG_MAGENTA_RGBA32 0xFF00FFFF -/* Maroon color { R:176, G:48, B:96, A:255 } */ -#define SG_MAROON_RGBA32 0xB03060FF -/* Web Maroon color { R:128, G:0, B:0, A:255 } */ -#define SG_WEB_MAROON_RGBA32 0x800000FF -/* Medium Aquamarine color { R:102, G:205, B:170, A:255 } */ -#define SG_MEDIUM_AQUAMARINE_RGBA32 0x66CDAAFF -/* Medium Blue color { R:0, G:0, B:205, A:255 } */ -#define SG_MEDIUM_BLUE_RGBA32 0x0000CDFF -/* Medium Orchid color { R:186, G:85, B:211, A:255 } */ -#define SG_MEDIUM_ORCHID_RGBA32 0xBA55D3FF -/* Medium Purple color { R:147, G:112, B:219, A:255 } */ -#define SG_MEDIUM_PURPLE_RGBA32 0x9370DBFF -/* Medium Sea Green color { R:60, G:179, B:113, A:255 } */ -#define SG_MEDIUM_SEA_GREEN_RGBA32 0x3CB371FF -/* Medium Slate Blue color { R:123, G:104, B:238, A:255 } */ -#define SG_MEDIUM_SLATE_BLUE_RGBA32 0x7B68EEFF -/* Medium Spring Green color { R:0, G:250, B:154, A:255 } */ -#define SG_MEDIUM_SPRING_GREEN_RGBA32 0x00FA9AFF -/* Medium Turquoise color { R:72, G:209, B:204, A:255 } */ -#define SG_MEDIUM_TURQUOISE_RGBA32 0x48D1CCFF -/* Medium Violet Red color { R:199, G:21, B:133, A:255 } */ -#define SG_MEDIUM_VIOLET_RED_RGBA32 0xC71585FF -/* Midnight Blue color { R:25, G:25, B:112, A:255 } */ -#define SG_MIDNIGHT_BLUE_RGBA32 0x191970FF -/* Mint Cream color { R:245, G:255, B:250, A:255 } */ -#define SG_MINT_CREAM_RGBA32 0xF5FFFAFF -/* Misty Rose color { R:255, G:228, B:225, A:255 } */ -#define SG_MISTY_ROSE_RGBA32 0xFFE4E1FF -/* Moccasin color { R:255, G:228, B:181, A:255 } */ -#define SG_MOCCASIN_RGBA32 0xFFE4B5FF -/* Navajo White color { R:255, G:222, B:173, A:255 } */ -#define SG_NAVAJO_WHITE_RGBA32 0xFFDEADFF -/* Navy Blue color { R:0, G:0, B:128, A:255 } */ -#define SG_NAVY_BLUE_RGBA32 0x000080FF -/* Old Lace color { R:253, G:245, B:230, A:255 } */ -#define SG_OLD_LACE_RGBA32 0xFDF5E6FF -/* Olive color { R:128, G:128, B:0, A:255 } */ -#define SG_OLIVE_RGBA32 0x808000FF -/* Olive Drab color { R:107, G:142, B:35, A:255 } */ -#define SG_OLIVE_DRAB_RGBA32 0x6B8E23FF -/* Orange color { R:255, G:165, B:0, A:255 } */ -#define SG_ORANGE_RGBA32 0xFFA500FF -/* Orange Red color { R:255, G:69, B:0, A:255 } */ -#define SG_ORANGE_RED_RGBA32 0xFF4500FF -/* Orchid color { R:218, G:112, B:214, A:255 } */ -#define SG_ORCHID_RGBA32 0xDA70D6FF -/* Pale Goldenrod color { R:238, G:232, B:170, A:255 } */ -#define SG_PALE_GOLDENROD_RGBA32 0xEEE8AAFF -/* Pale Green color { R:152, G:251, B:152, A:255 } */ -#define SG_PALE_GREEN_RGBA32 0x98FB98FF -/* Pale Turquoise color { R:175, G:238, B:238, A:255 } */ -#define SG_PALE_TURQUOISE_RGBA32 0xAFEEEEFF -/* Pale Violet Red color { R:219, G:112, B:147, A:255 } */ -#define SG_PALE_VIOLET_RED_RGBA32 0xDB7093FF -/* Papaya Whip color { R:255, G:239, B:213, A:255 } */ -#define SG_PAPAYA_WHIP_RGBA32 0xFFEFD5FF -/* Peach Puff color { R:255, G:218, B:185, A:255 } */ -#define SG_PEACH_PUFF_RGBA32 0xFFDAB9FF -/* Peru color { R:205, G:133, B:63, A:255 } */ -#define SG_PERU_RGBA32 0xCD853FFF -/* Pink color { R:255, G:192, B:203, A:255 } */ -#define SG_PINK_RGBA32 0xFFC0CBFF -/* Plum color { R:221, G:160, B:221, A:255 } */ -#define SG_PLUM_RGBA32 0xDDA0DDFF -/* Powder Blue color { R:176, G:224, B:230, A:255 } */ -#define SG_POWDER_BLUE_RGBA32 0xB0E0E6FF -/* Purple color { R:160, G:32, B:240, A:255 } */ -#define SG_PURPLE_RGBA32 0xA020F0FF -/* Web Purple color { R:128, G:0, B:128, A:255 } */ -#define SG_WEB_PURPLE_RGBA32 0x800080FF -/* Rebecca Purple color { R:102, G:51, B:153, A:255 } */ -#define SG_REBECCA_PURPLE_RGBA32 0x663399FF -/* Red color { R:255, G:0, B:0, A:255 } */ -#define SG_RED_RGBA32 0xFF0000FF -/* Rosy Brown color { R:188, G:143, B:143, A:255 } */ -#define SG_ROSY_BROWN_RGBA32 0xBC8F8FFF -/* Royal Blue color { R:65, G:105, B:225, A:255 } */ -#define SG_ROYAL_BLUE_RGBA32 0x4169E1FF -/* Saddle Brown color { R:139, G:69, B:19, A:255 } */ -#define SG_SADDLE_BROWN_RGBA32 0x8B4513FF -/* Salmon color { R:250, G:128, B:114, A:255 } */ -#define SG_SALMON_RGBA32 0xFA8072FF -/* Sandy Brown color { R:244, G:164, B:96, A:255 } */ -#define SG_SANDY_BROWN_RGBA32 0xF4A460FF -/* Sea Green color { R:46, G:139, B:87, A:255 } */ -#define SG_SEA_GREEN_RGBA32 0x2E8B57FF -/* Seashell color { R:255, G:245, B:238, A:255 } */ -#define SG_SEASHELL_RGBA32 0xFFF5EEFF -/* Sienna color { R:160, G:82, B:45, A:255 } */ -#define SG_SIENNA_RGBA32 0xA0522DFF -/* Silver color { R:192, G:192, B:192, A:255 } */ -#define SG_SILVER_RGBA32 0xC0C0C0FF -/* Sky Blue color { R:135, G:206, B:235, A:255 } */ -#define SG_SKY_BLUE_RGBA32 0x87CEEBFF -/* Slate Blue color { R:106, G:90, B:205, A:255 } */ -#define SG_SLATE_BLUE_RGBA32 0x6A5ACDFF -/* Slate Gray color { R:112, G:128, B:144, A:255 } */ -#define SG_SLATE_GRAY_RGBA32 0x708090FF -/* Snow color { R:255, G:250, B:250, A:255 } */ -#define SG_SNOW_RGBA32 0xFFFAFAFF -/* Spring Green color { R:0, G:255, B:127, A:255 } */ -#define SG_SPRING_GREEN_RGBA32 0x00FF7FFF -/* Steel Blue color { R:70, G:130, B:180, A:255 } */ -#define SG_STEEL_BLUE_RGBA32 0x4682B4FF -/* Tan color { R:210, G:180, B:140, A:255 } */ -#define SG_TAN_RGBA32 0xD2B48CFF -/* Teal color { R:0, G:128, B:128, A:255 } */ -#define SG_TEAL_RGBA32 0x008080FF -/* Thistle color { R:216, G:191, B:216, A:255 } */ -#define SG_THISTLE_RGBA32 0xD8BFD8FF -/* Tomato color { R:255, G:99, B:71, A:255 } */ -#define SG_TOMATO_RGBA32 0xFF6347FF -/* Transparent color { R:0, G:0, B:0, A:0 } */ -#define SG_TRANSPARENT_RGBA32 0x00000000 -/* Turquoise color { R:64, G:224, B:208, A:255 } */ -#define SG_TURQUOISE_RGBA32 0x40E0D0FF -/* Violet color { R:238, G:130, B:238, A:255 } */ -#define SG_VIOLET_RGBA32 0xEE82EEFF -/* Wheat color { R:245, G:222, B:179, A:255 } */ -#define SG_WHEAT_RGBA32 0xF5DEB3FF -/* White color { R:255, G:255, B:255, A:255 } */ -#define SG_WHITE_RGBA32 0xFFFFFFFF -/* White Smoke color { R:245, G:245, B:245, A:255 } */ -#define SG_WHITE_SMOKE_RGBA32 0xF5F5F5FF -/* Yellow color { R:255, G:255, B:0, A:255 } */ -#define SG_YELLOW_RGBA32 0xFFFF00FF -/* Yellow Green color { R:154, G:205, B:50, A:255 } */ -#define SG_YELLOW_GREEN_RGBA32 0x9ACD32FF - -#ifdef __cplusplus -} /* extern "C" */ - -inline sg_color sg_make_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return sg_make_color_4b(r, g, b, a); -} - -inline sg_color sg_make_color(uint32_t rgba) { - return sg_make_color_1i(rgba); -} - -inline sg_color sg_color_lerp(const sg_color& color_a, const sg_color& color_b, float amount) { - return sg_color_lerp(&color_a, &color_b, amount); -} - -inline sg_color sg_color_lerp_precise(const sg_color& color_a, const sg_color& color_b, float amount) { - return sg_color_lerp_precise(&color_a, &color_b, amount); -} - -inline sg_color sg_color_multiply(const sg_color& color, float scale) { - return sg_color_multiply(&color, scale); -} - -#endif /* __cplusplus */ - -#endif /* SOKOL_COLOR_INCLUDED */ - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_COLOR_IMPL -#define SOKOL_COLOR_IMPL_INCLUDED (1) - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -static inline float _sg_color_clamp(float v, float low, float high) { - if (v < low) { - return low; - } else if (v > high) { - return high; - } - return v; -} - -static inline float _sg_color_lerp(float a, float b, float amount) { - return a + (b - a) * amount; -} - -static inline float _sg_color_lerp_precise(float a, float b, float amount) { - return ((1.0f - amount) * a) + (b * amount); -} - -SOKOL_API_IMPL sg_color sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - sg_color result; - result.r = r / 255.0f; - result.g = g / 255.0f; - result.b = b / 255.0f; - result.a = a / 255.0f; - return result; -} - -SOKOL_API_IMPL sg_color sg_make_color_1i(uint32_t rgba) { - return sg_make_color_4b( - (uint8_t)(rgba >> 24), - (uint8_t)(rgba >> 16), - (uint8_t)(rgba >> 8), - (uint8_t)(rgba >> 0) - ); -} - -SOKOL_API_IMPL sg_color sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount) { - SOKOL_ASSERT(color_a); - SOKOL_ASSERT(color_b); - amount = _sg_color_clamp(amount, 0.0f, 1.0f); - sg_color result; - result.r = _sg_color_lerp(color_a->r, color_b->r, amount); - result.g = _sg_color_lerp(color_a->g, color_b->g, amount); - result.b = _sg_color_lerp(color_a->b, color_b->b, amount); - result.a = _sg_color_lerp(color_a->a, color_b->a, amount); - return result; -} - -SOKOL_API_IMPL sg_color sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount) { - SOKOL_ASSERT(color_a); - SOKOL_ASSERT(color_b); - amount = _sg_color_clamp(amount, 0.0f, 1.0f); - sg_color result; - result.r = _sg_color_lerp_precise(color_a->r, color_b->r, amount); - result.g = _sg_color_lerp_precise(color_a->g, color_b->g, amount); - result.b = _sg_color_lerp_precise(color_a->b, color_b->b, amount); - result.a = _sg_color_lerp_precise(color_a->a, color_b->a, amount); - return result; -} - -SOKOL_API_IMPL sg_color sg_color_multiply(const sg_color* color, float scale) { - SOKOL_ASSERT(color); - sg_color result; - result.r = color->r * scale; - result.g = color->g * scale; - result.b = color->b * scale; - result.a = color->a * scale; - return result; -} - -#endif /* SOKOL_COLOR_IMPL */ diff --git a/source/thirdparty/sokol/util/sokol_debugtext.h b/source/thirdparty/sokol/util/sokol_debugtext.h deleted file mode 100644 index 12ca7a64..00000000 --- a/source/thirdparty/sokol/util/sokol_debugtext.h +++ /dev/null @@ -1,4567 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_DEBUGTEXT_IMPL) -#define SOKOL_DEBUGTEXT_IMPL -#endif -#ifndef SOKOL_DEBUGTEXT_INCLUDED -/* - sokol_debugtext.h - simple ASCII debug text rendering on top of sokol_gfx.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_DEBUGTEXT_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_VSNPRINTF - the function name of an alternative vsnprintf() function (default: vsnprintf) - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_DEBUGTEXT_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_DEBUGTEXT_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - - If sokol_debugtext.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_DEBUGTEXT_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - Include the following headers before including sokol_debugtext.h: - - sokol_gfx.h - - FEATURES AND CONCEPTS - ===================== - - renders 8-bit ASCII text as fixed-size 8x8 pixel characters - - comes with 6 embedded 8-bit home computer fonts (each taking up 2 KBytes) - - easily plug in your own fonts - - create multiple contexts for rendering text in different layers or render passes - - STEP BY STEP - ============ - - --- to initialize sokol-debugtext, call sdtx_setup() *after* initializing - sokol-gfx: - - sdtx_setup(&(sdtx_desc_t){ ... }); - - To see any warnings and errors, you should always install a logging callback. - The easiest way is via sokol_log.h: - - #include "sokol_log.h" - - sdtx_setup(&(sdtx_desc_t){ - .logger.func = slog_func, - }); - - --- configure sokol-debugtext by populating the sdtx_desc_t struct: - - .context_pool_size (default: 8) - The max number of text contexts that can be created. - - .printf_buf_size (default: 4096) - The size of the internal text formatting buffer used by - sdtx_printf() and sdtx_vprintf(). - - .fonts (default: none) - An array of sdtx_font_desc_t structs used to configure the - fonts that can be used for rendering. To use all builtin - fonts call sdtx_setup() like this (in C99): - - sdtx_setup(&(sdtx_desc_t){ - .fonts = { - [0] = sdtx_font_kc853(), - [1] = sdtx_font_kc854(), - [2] = sdtx_font_z1013(), - [3] = sdtx_font_cpc(), - [4] = sdtx_font_c64(), - [5] = sdtx_font_oric() - } - }); - - For documentation on how to use you own font data, search - below for "USING YOUR OWN FONT DATA". - - .context - The setup parameters for the default text context. This will - be active right after sdtx_setup(), or when calling - sdtx_set_context(SDTX_DEFAULT_CONTEXT): - - .max_commands (default: 4096) - The max number of render commands that can be recorded - into the internal command buffer. This directly translates - to the number of render layer changes in a single frame. - - .char_buf_size (default: 4096) - The number of characters that can be rendered per frame in this - context, defines the size of an internal fixed-size vertex - buffer. Any additional characters will be silently ignored. - - .canvas_width (default: 640) - .canvas_height (default: 480) - The 'virtual canvas size' in pixels. This defines how big - characters will be rendered relative to the default framebuffer - dimensions. Each character occupies a grid of 8x8 'virtual canvas - pixels' (so a virtual canvas size of 640x480 means that 80x60 characters - fit on the screen). For rendering in a resizeable window, you - should dynamically update the canvas size in each frame by - calling sdtx_canvas(w, h). - - .tab_width (default: 4) - The width of a tab character in number of character cells. - - .color_format (default: 0) - .depth_format (default: 0) - .sample_count (default: 0) - The pixel format description for the default context needed - for creating the context's sg_pipeline object. When - rendering to the default framebuffer you can leave those - zero-initialized, in this case the proper values will be - filled in by sokol-gfx. You only need to provide non-default - values here when rendering to render targets with different - pixel format attributes than the default framebuffer. - - --- Before starting to render text, optionally call sdtx_canvas() to - dynamically resize the virtual canvas. This is recommended when - rendering to a resizeable window. The virtual canvas size can - also be used to scale text in relation to the display resolution. - - Examples when using sokol-app: - - - to render characters at 8x8 'physical pixels': - - sdtx_canvas(sapp_width(), sapp_height()); - - - to render characters at 16x16 physical pixels: - - sdtx_canvas(sapp_width()/2.0f, sapp_height()/2.0f); - - Do *not* use integer math here, since this will not look nice - when the render target size isn't divisible by 2. - - --- Optionally define the origin for the character grid with: - - sdtx_origin(x, y); - - The provided coordinates are in character grid cells, not in - virtual canvas pixels. E.g. to set the origin to 2 character tiles - from the left and top border: - - sdtx_origin(2, 2); - - You can define fractions, e.g. to start rendering half - a character tile from the top-left corner: - - sdtx_origin(0.5f, 0.5f); - - --- Optionally set a different font by calling: - - sdtx_font(font_index) - - sokol-debugtext provides 8 font slots which can be populated - with the builtin fonts or with user-provided font data, so - 'font_index' must be a number from 0 to 7. - - --- Position the text cursor with one of the following calls. All arguments - are in character grid cells as floats and relative to the - origin defined with sdtx_origin(): - - sdtx_pos(x, y) - sets absolute cursor position - sdtx_pos_x(x) - only set absolute x cursor position - sdtx_pos_y(y) - only set absolute y cursor position - - sdtx_move(x, y) - move cursor relative in x and y direction - sdtx_move_x(x) - move cursor relative only in x direction - sdtx_move_y(y) - move cursor relative only in y direction - - sdtx_crlf() - set cursor to beginning of next line - (same as sdtx_pos_x(0) + sdtx_move_y(1)) - sdtx_home() - resets the cursor to the origin - (same as sdtx_pos(0, 0)) - - --- Set a new text color with any of the following functions: - - sdtx_color3b(r, g, b) - RGB 0..255, A=255 - sdtx_color3f(r, g, b) - RGB 0.0f..1.0f, A=1.0f - sdtx_color4b(r, g, b, a) - RGBA 0..255 - sdtx_color4f(r, g, b, a) - RGBA 0.0f..1.0f - sdtx_color1i(uint32_t rgba) - ABGR (0xAABBGGRR) - - --- Output 8-bit ASCII text with the following functions: - - sdtx_putc(c) - output a single character - - sdtx_puts(str) - output a null-terminated C string, note that - this will *not* append a newline (so it behaves - differently than the CRT's puts() function) - - sdtx_putr(str, len) - 'put range' output the first 'len' characters of - a C string or until the zero character is encountered - - sdtx_printf(fmt, ...) - output with printf-formatting, note that you - can inject your own printf-compatible function - by overriding the SOKOL_VSNPRINTF define before - including the implementation - - sdtx_vprintf(fmt, args) - same as sdtx_printf() but with the arguments - provided in a va_list - - - Note that the text will not yet be rendered, only recorded for rendering - at a later time, the actual rendering happens when sdtx_draw() is called - inside a sokol-gfx render pass. - - This means also you can output text anywhere in the frame, it doesn't - have to be inside a render pass. - - Note that character codes <32 are reserved as control characters - and won't render anything. Currently only the following control - characters are implemented: - - \r - carriage return (same as sdtx_pos_x(0)) - \n - carriage return + line feed (same as stdx_crlf()) - \t - a tab character - - --- You can 'record' text into render layers, this allows to mix/interleave - sokol-debugtext rendering with other rendering operations inside - sokol-gfx render passes. To start recording text into a different render - layer, call: - - sdtx_layer(int layer_id) - - ...outside a sokol-gfx render pass. - - --- finally, from within a sokol-gfx render pass, call: - - sdtx_draw() - - ...for non-layered rendering, or to draw a specific layer: - - sdtx_draw_layer(int layer_id) - - NOTE that sdtx_draw() is equivalent to: - - sdtx_draw_layer(0) - - ...so sdtx_draw() will *NOT* render all text layers, instead it will - only render the 'default layer' 0. - - --- at the end of a frame (defined by the call to sg_commit()), sokol-debugtext - will rewind all contexts: - - - the internal vertex index is set to 0 - - the internal command index is set to 0 - - the current layer id is set to 0 - - the current font is set to 0 - - the cursor position is reset - - - RENDERING WITH MULTIPLE CONTEXTS - ================================ - Use multiple text contexts if you need to render debug text in different - sokol-gfx render passes, or want to render text to different layers - in the same render pass, each with its own set of parameters. - - To create a new text context call: - - sdtx_context ctx = sdtx_make_context(&(sdtx_context_desc_t){ ... }); - - The creation parameters in the sdtx_context_desc_t struct are the same - as already described above in the sdtx_setup() function: - - .char_buf_size -- max number of characters rendered in one frame, default: 4096 - .canvas_width -- the initial virtual canvas width, default: 640 - .canvas_height -- the initial virtual canvas height, default: 400 - .tab_width -- tab width in number of characters, default: 4 - .color_format -- color pixel format of target render pass - .depth_format -- depth pixel format of target render pass - .sample_count -- MSAA sample count of target render pass - - To make a new context the active context, call: - - sdtx_set_context(ctx) - - ...and after that call the text output functions as described above, and - finally, inside a sokol-gfx render pass, call sdtx_draw() to actually - render the text for this context. - - A context keeps track of the following parameters: - - - the active font - - the virtual canvas size - - the origin position - - the current cursor position - - the current tab width - - the current color - - and the current layer-id - - You can get the currently active context with: - - sdtx_get_context() - - To make the default context current, call sdtx_set_context() with the - special SDTX_DEFAULT_CONTEXT handle: - - sdtx_set_context(SDTX_DEFAULT_CONTEXT) - - Alternatively, use the function sdtx_default_context() to get the default - context handle: - - sdtx_set_context(sdtx_default_context()); - - To destroy a context, call: - - sdtx_destroy_context(ctx) - - If a context is set as active that no longer exists, all sokol-debugtext - functions that require an active context will silently fail. - - You can directly draw the recorded text in a specific context without - setting the active context: - - sdtx_context_draw(ctx) - sdtx_context_draw_layer(ctx, layer_id) - - USING YOUR OWN FONT DATA - ======================== - - Instead of the built-in fonts you can also plug your own font data - into sokol-debugtext by providing one or several sdtx_font_desc_t - structures in the sdtx_setup call. - - For instance to use a built-in font at slot 0, and a user-font at - font slot 1, the sdtx_setup() call might look like this: - - sdtx_setup(&sdtx_desc_t){ - .fonts = { - [0] = sdtx_font_kc853(), - [1] = { - .data = { - .ptr = my_font_data, - .size = sizeof(my_font_data) - }, - .first_char = ..., - .last_char = ... - } - } - }); - - Where 'my_font_data' is a byte array where every character is described - by 8 bytes arranged like this: - - bits - 7 6 5 4 3 2 1 0 - . . . X X . . . byte 0: 0x18 - . . X X X X . . byte 1: 0x3C - . X X . . X X . byte 2: 0x66 - . X X . . X X . byte 3: 0x66 - . X X X X X X . byte 4: 0x7E - . X X . . X X . byte 5: 0x66 - . X X . . X X . byte 6: 0x66 - . . . . . . . . byte 7: 0x00 - - A complete font consists of 256 characters, resulting in 2048 bytes for - the font data array (but note that the character codes 0..31 will never - be rendered). - - If you provide such a complete font data array, you can drop the .first_char - and .last_char initialization parameters since those default to 0 and 255, - note that you can also use the SDTX_RANGE() helper macro to build the - .data item: - - sdtx_setup(&sdtx_desc_t){ - .fonts = { - [0] = sdtx_font_kc853(), - [1] = { - .data = SDTX_RANGE(my_font_data) - } - } - }); - - If the font doesn't define all 256 character tiles, or you don't need an - entire 256-character font and want to save a couple of bytes, use the - .first_char and .last_char initialization parameters to define a sub-range. - For instance if the font only contains the characters between the Space - (ASCII code 32) and uppercase character 'Z' (ASCII code 90): - - sdtx_setup(&sdtx_desc_t){ - .fonts = { - [0] = sdtx_font_kc853(), - [1] = { - .data = SDTX_RANGE(my_font_data), - .first_char = 32, // could also write ' ' - .last_char = 90 // could also write 'Z' - } - } - }); - - Character tiles that haven't been defined in the font will be rendered - as a solid 8x8 quad. - - - 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); - } - - ... - sdtx_setup(&(sdtx_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" - - sdtx_setup(&(sdtx_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. 'sdtx' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SDTX_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_debugtext.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-debugtext like this: - - sdtx_setup(&(sdtx_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) 2020 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. -*/ -#define SOKOL_DEBUGTEXT_INCLUDED (1) -#include -#include -#include // size_t -#include // va_list - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_debugtext.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_DEBUGTEXT_API_DECL) -#define SOKOL_DEBUGTEXT_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_DEBUGTEXT_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_DEBUGTEXT_IMPL) -#define SOKOL_DEBUGTEXT_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_DEBUGTEXT_API_DECL __declspec(dllimport) -#else -#define SOKOL_DEBUGTEXT_API_DECL extern -#endif -#endif - -#if defined(__GNUC__) -#define SOKOL_DEBUGTEXT_PRINTF_ATTR __attribute__((format(printf, 1, 2))) -#else -#define SOKOL_DEBUGTEXT_PRINTF_ATTR -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - sdtx_log_item_t - - Log items are defined via X-Macros, and expanded to an - enum 'sdtx_log_item' - and in debug mode only - corresponding strings. - - Used as parameter in the logging callback. -*/ -#define _SDTX_LOG_ITEMS \ - _SDTX_LOGITEM_XMACRO(OK, "Ok") \ - _SDTX_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SDTX_LOGITEM_XMACRO(ADD_COMMIT_LISTENER_FAILED, "sg_add_commit_listener() failed") \ - _SDTX_LOGITEM_XMACRO(COMMAND_BUFFER_FULL, "command buffer full (adjust via sdtx_context_desc_t.max_commands)") \ - _SDTX_LOGITEM_XMACRO(CONTEXT_POOL_EXHAUSTED, "context pool exhausted (adjust via sdtx_desc_t.context_pool_size)") \ - _SDTX_LOGITEM_XMACRO(CANNOT_DESTROY_DEFAULT_CONTEXT, "cannot destroy default context") \ - -#define _SDTX_LOGITEM_XMACRO(item,msg) SDTX_LOGITEM_##item, -typedef enum sdtx_log_item_t { - _SDTX_LOG_ITEMS -} sdtx_log_item_t; -#undef _SDTX_LOGITEM_XMACRO - -/* - sdtx_logger_t - - Used in sdtx_desc_t to provide a custom logging and error reporting - callback to sokol-debugtext. -*/ -typedef struct sdtx_logger_t { - void (*func)( - const char* tag, // always "sdtx" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SDTX_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_debugtext.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} sdtx_logger_t; - -/* a rendering context handle */ -typedef struct sdtx_context { uint32_t id; } sdtx_context; - -/* the default context handle */ -static const sdtx_context SDTX_DEFAULT_CONTEXT = { 0x00010001 }; - -/* - sdtx_range is a pointer-size-pair struct used to pass memory - blobs into sokol-debugtext. When initialized from a value type - (array or struct), use the SDTX_RANGE() macro to build - an sdtx_range struct. -*/ -typedef struct sdtx_range { - const void* ptr; - size_t size; -} sdtx_range; - -// disabling this for every includer isn't great, but the warning is also quite pointless -#if defined(_MSC_VER) -#pragma warning(disable:4221) /* /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' */ -#pragma warning(disable:4204) /* VS2015: nonstandard extension used: non-constant aggregate initializer */ -#endif -#if defined(__cplusplus) -#define SDTX_RANGE(x) sdtx_range{ &x, sizeof(x) } -#else -#define SDTX_RANGE(x) (sdtx_range){ &x, sizeof(x) } -#endif - -/* - sdtx_font_desc_t - - Describes the pixel data of a font. A font consists of up to - 256 8x8 character tiles, where each character tile is described - by 8 consecutive bytes, each byte describing 8 pixels. - - For instance the character 'A' could look like this (this is also - how most home computers used to describe their fonts in ROM): - - bits - 7 6 5 4 3 2 1 0 - . . . X X . . . byte 0: 0x18 - . . X X X X . . byte 1: 0x3C - . X X . . X X . byte 2: 0x66 - . X X . . X X . byte 3: 0x66 - . X X X X X X . byte 4: 0x7E - . X X . . X X . byte 5: 0x66 - . X X . . X X . byte 6: 0x66 - . . . . . . . . byte 7: 0x00 - */ -#define SDTX_MAX_FONTS (8) - -typedef struct sdtx_font_desc_t { - sdtx_range data; // pointer to and size of font pixel data - uint8_t first_char; // first character index in font pixel data - uint8_t last_char; // last character index in font pixel data, inclusive (default: 255) -} sdtx_font_desc_t; - -/* - sdtx_context_desc_t - - Describes the initialization parameters of a rendering context. Creating - additional rendering contexts is useful if you want to render in - different sokol-gfx rendering passes, or when rendering several layers - of text. -*/ -typedef struct sdtx_context_desc_t { - int max_commands; // max number of draw commands, each layer transition counts as a command, default: 4096 - int char_buf_size; // max number of characters rendered in one frame, default: 4096 - float canvas_width; // the initial virtual canvas width, default: 640 - float canvas_height; // the initial virtual canvas height, default: 400 - int tab_width; // tab width in number of characters, default: 4 - sg_pixel_format color_format; // color pixel format of target render pass - sg_pixel_format depth_format; // depth pixel format of target render pass - int sample_count; // MSAA sample count of target render pass -} sdtx_context_desc_t; - -/* - sdtx_allocator_t - - Used in sdtx_desc_t to provide custom memory-alloc and -free functions - to sokol_debugtext.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct sdtx_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sdtx_allocator_t; - -/* - sdtx_desc_t - - Describes the sokol-debugtext API initialization parameters. Passed - to the sdtx_setup() function. - - NOTE: to populate the fonts item array with builtin fonts, use any - of the following functions: - - sdtx_font_kc853() - sdtx_font_kc854() - sdtx_font_z1013() - sdtx_font_cpc() - sdtx_font_c64() - sdtx_font_oric() -*/ -typedef struct sdtx_desc_t { - int context_pool_size; // max number of rendering contexts that can be created, default: 8 - int printf_buf_size; // size of internal buffer for snprintf(), default: 4096 - sdtx_font_desc_t fonts[SDTX_MAX_FONTS]; // up to 8 fonts descriptions - sdtx_context_desc_t context; // the default context creation parameters - sdtx_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) - sdtx_logger_t logger; // optional log override function (default: NO LOGGING) -} sdtx_desc_t; - -/* initialization/shutdown */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_setup(const sdtx_desc_t* desc); -SOKOL_DEBUGTEXT_API_DECL void sdtx_shutdown(void); - -/* builtin font data (use to populate sdtx_desc.font[]) */ -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_kc853(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_kc854(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_z1013(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_cpc(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_c64(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_font_desc_t sdtx_font_oric(void); - -/* context functions */ -SOKOL_DEBUGTEXT_API_DECL sdtx_context sdtx_make_context(const sdtx_context_desc_t* desc); -SOKOL_DEBUGTEXT_API_DECL void sdtx_destroy_context(sdtx_context ctx); -SOKOL_DEBUGTEXT_API_DECL void sdtx_set_context(sdtx_context ctx); -SOKOL_DEBUGTEXT_API_DECL sdtx_context sdtx_get_context(void); -SOKOL_DEBUGTEXT_API_DECL sdtx_context sdtx_default_context(void); - -/* drawing functions (call inside sokol-gfx render pass) */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_draw(void); -SOKOL_DEBUGTEXT_API_DECL void sdtx_context_draw(sdtx_context ctx); -SOKOL_DEBUGTEXT_API_DECL void sdtx_draw_layer(int layer_id); -SOKOL_DEBUGTEXT_API_DECL void sdtx_context_draw_layer(sdtx_context ctx, int layer_id); - -/* switch render layer */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_layer(int layer_id); - -/* switch to a different font */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_font(int font_index); - -/* set a new virtual canvas size in screen pixels */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_canvas(float w, float h); - -/* set a new origin in character grid coordinates */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_origin(float x, float y); - -/* cursor movement functions (relative to origin in character grid coordinates) */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_home(void); -SOKOL_DEBUGTEXT_API_DECL void sdtx_pos(float x, float y); -SOKOL_DEBUGTEXT_API_DECL void sdtx_pos_x(float x); -SOKOL_DEBUGTEXT_API_DECL void sdtx_pos_y(float y); -SOKOL_DEBUGTEXT_API_DECL void sdtx_move(float dx, float dy); -SOKOL_DEBUGTEXT_API_DECL void sdtx_move_x(float dx); -SOKOL_DEBUGTEXT_API_DECL void sdtx_move_y(float dy); -SOKOL_DEBUGTEXT_API_DECL void sdtx_crlf(void); - -/* set the current text color */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_color3b(uint8_t r, uint8_t g, uint8_t b); // RGB 0..255, A=255 -SOKOL_DEBUGTEXT_API_DECL void sdtx_color3f(float r, float g, float b); // RGB 0.0f..1.0f, A=1.0f -SOKOL_DEBUGTEXT_API_DECL void sdtx_color4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); // RGBA 0..255 -SOKOL_DEBUGTEXT_API_DECL void sdtx_color4f(float r, float g, float b, float a); // RGBA 0.0f..1.0f -SOKOL_DEBUGTEXT_API_DECL void sdtx_color1i(uint32_t rgba); // ABGR 0xAABBGGRR - -/* text rendering */ -SOKOL_DEBUGTEXT_API_DECL void sdtx_putc(char c); -SOKOL_DEBUGTEXT_API_DECL void sdtx_puts(const char* str); // does NOT append newline! -SOKOL_DEBUGTEXT_API_DECL void sdtx_putr(const char* str, int len); // 'put range', also stops at zero-char -SOKOL_DEBUGTEXT_API_DECL int sdtx_printf(const char* fmt, ...) SOKOL_DEBUGTEXT_PRINTF_ATTR; -SOKOL_DEBUGTEXT_API_DECL int sdtx_vprintf(const char* fmt, va_list args); - -#ifdef __cplusplus -} /* extern "C" */ -/* C++ const-ref wrappers */ -inline void sdtx_setup(const sdtx_desc_t& desc) { return sdtx_setup(&desc); } -inline sdtx_context sdtx_make_context(const sdtx_context_desc_t& desc) { return sdtx_make_context(&desc); } -#endif -#endif /* SOKOL_DEBUGTEXT_INCLUDED */ - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_DEBUGTEXT_IMPL -#define SOKOL_DEBUGTEXT_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sdtx_desc_t.allocator to override memory allocation functions" -#endif - -#include // memset -#include // fmodf -#include // for vsnprintf -#include // malloc/free - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif -#ifndef _SOKOL_UNUSED - #define _SOKOL_UNUSED(x) (void)(x) -#endif - -#ifndef SOKOL_VSNPRINTF -#include -#define SOKOL_VSNPRINTF vsnprintf -#endif - -#define _sdtx_def(val, def) (((val) == 0) ? (def) : (val)) -#define _SDTX_INIT_COOKIE (0xACBAABCA) - -#define _SDTX_DEFAULT_MAX_COMMANDS (4096) -#define _SDTX_DEFAULT_CONTEXT_POOL_SIZE (8) -#define _SDTX_DEFAULT_CHAR_BUF_SIZE (4096) -#define _SDTX_DEFAULT_PRINTF_BUF_SIZE (4096) -#define _SDTX_DEFAULT_CANVAS_WIDTH (640) -#define _SDTX_DEFAULT_CANVAS_HEIGHT (480) -#define _SDTX_DEFAULT_TAB_WIDTH (4) -#define _SDTX_DEFAULT_COLOR (0xFF00FFFF) -#define _SDTX_INVALID_SLOT_INDEX (0) -#define _SDTX_SLOT_SHIFT (16) -#define _SDTX_MAX_POOL_SIZE (1<<_SDTX_SLOT_SHIFT) -#define _SDTX_SLOT_MASK (_SDTX_MAX_POOL_SIZE-1) - -/* embedded font data */ -static const uint8_t _sdtx_font_kc853[2048] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xFF, // 00 - 0x00, 0x00, 0x22, 0x72, 0x22, 0x3E, 0x00, 0x00, // 01 - 0x00, 0x00, 0x12, 0x32, 0x7E, 0x32, 0x12, 0x00, // 02 - 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0xB9, 0x81, // 03 - 0x55, 0xFF, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 04 - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 05 - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, // 06 - 0x00, 0x00, 0x3C, 0x42, 0x42, 0x7E, 0x00, 0x00, // 07 - 0x00, 0x10, 0x30, 0x7E, 0x30, 0x10, 0x00, 0x00, // 08 - 0x00, 0x08, 0x0C, 0x7E, 0x0C, 0x08, 0x00, 0x00, // 09 - 0x00, 0x10, 0x10, 0x10, 0x7C, 0x38, 0x10, 0x00, // 0A - 0x08, 0x1C, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x00, // 0B - 0x38, 0x30, 0x28, 0x08, 0x08, 0x08, 0x3E, 0x00, // 0C - 0x00, 0x00, 0x12, 0x32, 0x7E, 0x30, 0x10, 0x00, // 0D - 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, // 0E - 0x3E, 0x7C, 0x7C, 0x3E, 0x3E, 0x7C, 0xF8, 0xF8, // 0F - 0x38, 0x30, 0x28, 0x04, 0x04, 0x04, 0x04, 0x00, // 10 - 0x7F, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x00, // 11 - 0x00, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x7F, // 12 - 0x7E, 0x81, 0x9D, 0xA1, 0xB9, 0x85, 0x85, 0xB9, // 13 - 0x00, 0x3C, 0x42, 0x5A, 0x5A, 0x42, 0x3C, 0x00, // 14 - 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11, // 15 - 0x00, 0x7F, 0x22, 0x72, 0x27, 0x22, 0x7F, 0x00, // 16 - 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, // 17 - 0x00, 0x01, 0x09, 0x0D, 0x7F, 0x0D, 0x09, 0x01, // 18 - 0x00, 0x90, 0xB0, 0xFE, 0xB0, 0x90, 0x00, 0x00, // 19 - 0x00, 0x08, 0x7C, 0x06, 0x7C, 0x08, 0x00, 0x00, // 1A - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // 1B - 0x7E, 0x81, 0xA1, 0xA1, 0xA1, 0xA1, 0xBD, 0x81, // 1C - 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0xA5, 0x81, // 1D - 0x7E, 0x81, 0x99, 0xA1, 0xA1, 0xA1, 0x99, 0x81, // 1E - 0x00, 0x10, 0x3E, 0x60, 0x3E, 0x10, 0x00, 0x00, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, // 21 - 0x00, 0x66, 0x66, 0xCC, 0x00, 0x00, 0x00, 0x00, // 22 - 0x00, 0x36, 0x7F, 0x36, 0x36, 0x7F, 0x36, 0x00, // 23 - 0x18, 0x3E, 0x6C, 0x3E, 0x1B, 0x1B, 0x7E, 0x18, // 24 - 0x00, 0x63, 0x66, 0x0C, 0x18, 0x36, 0x66, 0x00, // 25 - 0x18, 0x24, 0x28, 0x11, 0x2A, 0x44, 0x4A, 0x31, // 26 - 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // 27 - 0x00, 0x18, 0x30, 0x30, 0x30, 0x30, 0x18, 0x00, // 28 - 0x00, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x00, // 29 - 0x00, 0x00, 0x24, 0x18, 0x7E, 0x18, 0x24, 0x00, // 2A - 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, // 2C - 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // 2E - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00, 0x00, // 2F - 0x00, 0x3C, 0x6E, 0x6E, 0x76, 0x76, 0x3C, 0x00, // 30 - 0x00, 0x1C, 0x3C, 0x0C, 0x0C, 0x0C, 0x3E, 0x00, // 31 - 0x00, 0x3C, 0x66, 0x06, 0x3C, 0x60, 0x7E, 0x00, // 32 - 0x00, 0x3C, 0x66, 0x0C, 0x06, 0x66, 0x3C, 0x00, // 33 - 0x00, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x00, // 34 - 0x00, 0x7E, 0x60, 0x7C, 0x06, 0x66, 0x3C, 0x00, // 35 - 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, // 36 - 0x00, 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, // 37 - 0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // 38 - 0x00, 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x3C, 0x00, // 39 - 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, // 3A - 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x30, 0x00, // 3B - 0x00, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, // 3C - 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, // 3D - 0x00, 0x00, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x00, // 3E - 0x00, 0x3C, 0x66, 0x06, 0x1C, 0x18, 0x00, 0x18, // 3F - 0x3C, 0x42, 0x81, 0x35, 0x49, 0x49, 0x49, 0x36, // 40 - 0x00, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 41 - 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, // 42 - 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x00, // 43 - 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // 44 - 0x00, 0x7E, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, // 45 - 0x00, 0x7E, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00, // 46 - 0x00, 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x3C, 0x00, // 47 - 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // 48 - 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 49 - 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, // 4A - 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x63, 0x00, // 4B - 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, // 4C - 0x00, 0x63, 0x77, 0x6B, 0x63, 0x63, 0x63, 0x00, // 4D - 0x00, 0x63, 0x73, 0x6B, 0x67, 0x63, 0x63, 0x00, // 4E - 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 4F - 0x00, 0x7C, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, // 50 - 0x00, 0x3C, 0x66, 0x66, 0x6E, 0x66, 0x3A, 0x01, // 51 - 0x00, 0x7C, 0x66, 0x7C, 0x6C, 0x66, 0x63, 0x00, // 52 - 0x00, 0x3C, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, // 53 - 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 54 - 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 55 - 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 56 - 0x00, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, // 57 - 0x00, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x66, 0x00, // 58 - 0x00, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x00, // 59 - 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, // 5A - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5B - 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 5C - 0x00, 0x7E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, // 5D - 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x00, // 5E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // 5F - 0x7E, 0x81, 0x99, 0xA1, 0xA1, 0x99, 0x81, 0x7E, // 60 - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3B, 0x00, // 61 - 0x00, 0x60, 0x60, 0x78, 0x6C, 0x6C, 0x78, 0x00, // 62 - 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, // 63 - 0x00, 0x06, 0x06, 0x1E, 0x36, 0x36, 0x1E, 0x00, // 64 - 0x00, 0x00, 0x38, 0x6C, 0x7C, 0x60, 0x38, 0x00, // 65 - 0x00, 0x1E, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x00, // 66 - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x3F, 0x06, 0x3C, // 67 - 0x00, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x00, // 68 - 0x00, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, // 69 - 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x30, // 6A - 0x00, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, // 6B - 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x00, // 6C - 0x00, 0x00, 0x36, 0x7F, 0x6B, 0x63, 0x63, 0x00, // 6D - 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, // 6E - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // 6F - 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, // 70 - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x06, // 71 - 0x00, 0x00, 0x36, 0x38, 0x30, 0x30, 0x30, 0x00, // 72 - 0x00, 0x00, 0x1C, 0x30, 0x1C, 0x06, 0x3C, 0x00, // 73 - 0x00, 0x18, 0x18, 0x3C, 0x18, 0x18, 0x0C, 0x00, // 74 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 75 - 0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x00, // 76 - 0x00, 0x00, 0x63, 0x63, 0x6B, 0x7F, 0x36, 0x00, // 77 - 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // 78 - 0x00, 0x00, 0x66, 0x3C, 0x18, 0x30, 0x60, 0x00, // 79 - 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, // 7A - 0x66, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3B, 0x00, // 7B - 0x66, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // 7C - 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 7D - 0x00, 0x38, 0x6C, 0x78, 0x6C, 0x78, 0x60, 0x60, // 7E - 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, // 7F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x00, // 80 - 0xFF, 0xFF, 0xDD, 0x8D, 0xDD, 0xC1, 0xFF, 0xFF, // 81 - 0xFF, 0xFF, 0xED, 0xCD, 0x81, 0xCD, 0xED, 0xFF, // 82 - 0x81, 0x7E, 0x46, 0x5A, 0x46, 0x5A, 0x46, 0x7E, // 83 - 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, // 84 - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // 85 - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, // 86 - 0xFF, 0xFF, 0xC3, 0xBD, 0xBD, 0x81, 0xFF, 0xFF, // 87 - 0xFF, 0xEF, 0xCF, 0x81, 0xCF, 0xEF, 0xFF, 0xFF, // 88 - 0xFF, 0xF7, 0xF3, 0x81, 0xF3, 0xF7, 0xFF, 0xFF, // 89 - 0xFF, 0xEF, 0xEF, 0xEF, 0x83, 0xC7, 0xEF, 0xFF, // 8A - 0xF7, 0xE3, 0xC1, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // 8B - 0xC7, 0xCF, 0xD7, 0xF7, 0xF7, 0xF7, 0xC1, 0xFF, // 8C - 0xFF, 0xFF, 0xED, 0xCD, 0x81, 0xCF, 0xEF, 0xFF, // 8D - 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 8E - 0xC1, 0x83, 0x83, 0xC1, 0xC1, 0x83, 0x07, 0x07, // 8F - 0xC7, 0xCF, 0xD7, 0xFB, 0xFB, 0xFB, 0xFB, 0xFF, // 90 - 0x80, 0xF7, 0xE3, 0xD5, 0xF7, 0xF7, 0xF7, 0xFF, // 91 - 0xFF, 0xF7, 0xF7, 0xF7, 0xD5, 0xE3, 0xF7, 0x80, // 92 - 0x81, 0x7E, 0x62, 0x5E, 0x46, 0x7A, 0x7A, 0x46, // 93 - 0xFF, 0xC3, 0xBD, 0xA5, 0xA5, 0xBD, 0xC3, 0xFF, // 94 - 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE, // 95 - 0xFF, 0x80, 0xDD, 0x8D, 0xD8, 0xDD, 0x80, 0xFF, // 96 - 0xEE, 0xDD, 0xBB, 0x77, 0xEE, 0xDD, 0xBB, 0x77, // 97 - 0xFF, 0xFE, 0xF6, 0xF2, 0x80, 0xF2, 0xF6, 0xFE, // 98 - 0xFF, 0x6F, 0x4F, 0x01, 0x4F, 0x6F, 0xFF, 0xFF, // 99 - 0xFF, 0xF7, 0x83, 0xF9, 0x83, 0xF7, 0xFF, 0xFF, // 9A - 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, // 9B - 0x81, 0x7E, 0x5E, 0x5E, 0x5E, 0x5E, 0x42, 0x7E, // 9C - 0x81, 0x7E, 0x46, 0x5A, 0x46, 0x5A, 0x5A, 0x7E, // 9D - 0x81, 0x7E, 0x66, 0x5E, 0x5E, 0x5E, 0x66, 0x7E, // 9E - 0xFF, 0xEF, 0xC1, 0x9F, 0xC1, 0xEF, 0xFF, 0xFF, // 9F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A0 - 0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xE7, 0xFF, // A1 - 0xFF, 0x99, 0x99, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, // A2 - 0xFF, 0xC9, 0x80, 0xC9, 0xC9, 0x80, 0xC9, 0xFF, // A3 - 0xE7, 0xC1, 0x93, 0xC1, 0xE4, 0xE4, 0x81, 0xE7, // A4 - 0xFF, 0x9C, 0x99, 0xF3, 0xE7, 0xC9, 0x99, 0xFF, // A5 - 0xE7, 0xDB, 0xD7, 0xEE, 0xD5, 0xBB, 0xB5, 0xCE, // A6 - 0xFF, 0xE7, 0xE7, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, // A7 - 0xFF, 0xE7, 0xCF, 0xCF, 0xCF, 0xCF, 0xE7, 0xFF, // A8 - 0xFF, 0xE7, 0xF3, 0xF3, 0xF3, 0xF3, 0xE7, 0xFF, // A9 - 0xFF, 0xFF, 0xDB, 0xE7, 0x81, 0xE7, 0xDB, 0xFF, // AA - 0xFF, 0xFF, 0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xFF, // AB - 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF, 0xFF, // AC - 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, // AD - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, // AE - 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3F, 0xFF, 0xFF, // AF - 0xFF, 0xC3, 0x91, 0x91, 0x89, 0x89, 0xC3, 0xFF, // B0 - 0xFF, 0xE3, 0xC3, 0xF3, 0xF3, 0xF3, 0xC1, 0xFF, // B1 - 0xFF, 0xC3, 0x99, 0xF9, 0xC3, 0x9F, 0x81, 0xFF, // B2 - 0xFF, 0xC3, 0x99, 0xF3, 0xF9, 0x99, 0xC3, 0xFF, // B3 - 0xFF, 0xC3, 0x93, 0x33, 0x01, 0xF3, 0xF3, 0xFF, // B4 - 0xFF, 0x81, 0x9F, 0x83, 0xF9, 0x99, 0xC3, 0xFF, // B5 - 0xFF, 0xC3, 0x9F, 0x83, 0x99, 0x99, 0xC3, 0xFF, // B6 - 0xFF, 0x81, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0xFF, // B7 - 0xFF, 0xC3, 0x99, 0xC3, 0x99, 0x99, 0xC3, 0xFF, // B8 - 0xFF, 0xC3, 0x99, 0x99, 0xC1, 0xF9, 0xC3, 0xFF, // B9 - 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xE7, 0xE7, 0xFF, // BA - 0xFF, 0xFF, 0xE7, 0xFF, 0xE7, 0xE7, 0xCF, 0xFF, // BB - 0xFF, 0xFF, 0xE7, 0xCF, 0x9F, 0xCF, 0xE7, 0xFF, // BC - 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xC1, 0xFF, 0xFF, // BD - 0xFF, 0xFF, 0xCF, 0xE7, 0xF3, 0xE7, 0xCF, 0xFF, // BE - 0xFF, 0xC3, 0x99, 0xF9, 0xE3, 0xE7, 0xFF, 0xE7, // BF - 0xC3, 0xBD, 0x7E, 0xCA, 0xB6, 0xB6, 0xB6, 0xC9, // C0 - 0xFF, 0xC3, 0x99, 0x99, 0x81, 0x99, 0x99, 0xFF, // C1 - 0xFF, 0x83, 0x99, 0x83, 0x99, 0x99, 0x83, 0xFF, // C2 - 0xFF, 0xC3, 0x99, 0x9F, 0x9F, 0x99, 0xC3, 0xFF, // C3 - 0xFF, 0x83, 0x99, 0x99, 0x99, 0x99, 0x83, 0xFF, // C4 - 0xFF, 0x81, 0x9F, 0x83, 0x9F, 0x9F, 0x81, 0xFF, // C5 - 0xFF, 0x81, 0x9F, 0x83, 0x9F, 0x9F, 0x9F, 0xFF, // C6 - 0xFF, 0xC3, 0x99, 0x9F, 0x91, 0x99, 0xC3, 0xFF, // C7 - 0xFF, 0x99, 0x99, 0x81, 0x99, 0x99, 0x99, 0xFF, // C8 - 0xFF, 0xC3, 0xE7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF, // C9 - 0xFF, 0xE1, 0xF3, 0xF3, 0xF3, 0x93, 0xC7, 0xFF, // CA - 0xFF, 0x99, 0x93, 0x87, 0x93, 0x99, 0x9C, 0xFF, // CB - 0xFF, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x81, 0xFF, // CC - 0xFF, 0x9C, 0x88, 0x94, 0x9C, 0x9C, 0x9C, 0xFF, // CD - 0xFF, 0x9C, 0x8C, 0x94, 0x98, 0x9C, 0x9C, 0xFF, // CE - 0xFF, 0xC3, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, // CF - 0xFF, 0x83, 0x99, 0x83, 0x9F, 0x9F, 0x9F, 0xFF, // D0 - 0xFF, 0xC3, 0x99, 0x99, 0x91, 0x99, 0xC5, 0xFE, // D1 - 0xFF, 0x83, 0x99, 0x83, 0x93, 0x99, 0x9C, 0xFF, // D2 - 0xFF, 0xC3, 0x9F, 0xC3, 0xF9, 0x99, 0xC3, 0xFF, // D3 - 0xFF, 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // D4 - 0xFF, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, // D5 - 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF, // D6 - 0xFF, 0x9C, 0x9C, 0x94, 0x94, 0x80, 0xC9, 0xFF, // D7 - 0xFF, 0x99, 0xC3, 0xE7, 0xE7, 0xC3, 0x99, 0xFF, // D8 - 0xFF, 0x99, 0xC3, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // D9 - 0xFF, 0x81, 0xF3, 0xE7, 0xCF, 0x9F, 0x81, 0xFF, // DA - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DB - 0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // DC - 0xFF, 0x81, 0xF9, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, // DD - 0xFF, 0xFF, 0xFF, 0xF7, 0xE3, 0xC9, 0xFF, 0xFF, // DE - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, // DF - 0x81, 0x7E, 0x66, 0x5E, 0x5E, 0x66, 0x7E, 0x81, // E0 - 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC4, 0xFF, // E1 - 0xFF, 0x9F, 0x9F, 0x87, 0x93, 0x93, 0x87, 0xFF, // E2 - 0xFF, 0xFF, 0xC3, 0x99, 0x9F, 0x99, 0xC3, 0xFF, // E3 - 0xFF, 0xF9, 0xF9, 0xE1, 0xC9, 0xC9, 0xE1, 0xFF, // E4 - 0xFF, 0xFF, 0xC7, 0x93, 0x83, 0x9F, 0xC7, 0xFF, // E5 - 0xFF, 0xE1, 0xE7, 0x81, 0xE7, 0xE7, 0xE7, 0xFF, // E6 - 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0xC0, 0xF9, 0xC3, // E7 - 0xFF, 0x9F, 0x9F, 0x93, 0x89, 0x99, 0x99, 0xFF, // E8 - 0xFF, 0xE7, 0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // E9 - 0xFF, 0xE7, 0xFF, 0xC7, 0xE7, 0xE7, 0xE7, 0xCF, // EA - 0xFF, 0x9F, 0x99, 0x93, 0x87, 0x93, 0x99, 0xFF, // EB - 0xFF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xE7, 0xFF, // EC - 0xFF, 0xFF, 0xC9, 0x80, 0x94, 0x9C, 0x9C, 0xFF, // ED - 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x99, 0x99, 0xFF, // EE - 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC3, 0xFF, // EF - 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x9F, 0x9F, // F0 - 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0xC1, 0xF9, 0xF9, // F1 - 0xFF, 0xFF, 0xC9, 0xC7, 0xCF, 0xCF, 0xCF, 0xFF, // F2 - 0xFF, 0xFF, 0xE3, 0xCF, 0xE3, 0xF9, 0xC3, 0xFF, // F3 - 0xFF, 0xE7, 0xE7, 0xC3, 0xE7, 0xE7, 0xF3, 0xFF, // F4 - 0xFF, 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, // F5 - 0xFF, 0xFF, 0x99, 0x99, 0xC3, 0xC3, 0xE7, 0xFF, // F6 - 0xFF, 0xFF, 0x9C, 0x9C, 0x94, 0x80, 0xC9, 0xFF, // F7 - 0xFF, 0xFF, 0x99, 0xC3, 0xE7, 0xC3, 0x99, 0xFF, // F8 - 0xFF, 0xFF, 0x99, 0xC3, 0xE7, 0xCF, 0x9F, 0xFF, // F9 - 0xFF, 0xFF, 0x81, 0xF3, 0xE7, 0xCF, 0x81, 0xFF, // FA - 0x99, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC4, 0xFF, // FB - 0x99, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC3, 0xFF, // FC - 0x99, 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, // FD - 0xFF, 0xC7, 0x93, 0x87, 0x93, 0x87, 0x9F, 0x9F, // FE - 0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x00, // FF -}; -static const uint8_t _sdtx_font_kc854[2048] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xFF, // 00 - 0x00, 0x00, 0x22, 0x72, 0x22, 0x3E, 0x00, 0x00, // 01 - 0x00, 0x00, 0x12, 0x32, 0x7E, 0x32, 0x12, 0x00, // 02 - 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0xB9, 0x81, // 03 - 0x55, 0xFF, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 04 - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 05 - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, // 06 - 0x00, 0x00, 0x3C, 0x42, 0x42, 0x7E, 0x00, 0x00, // 07 - 0x00, 0x10, 0x30, 0x7E, 0x30, 0x10, 0x00, 0x00, // 08 - 0x00, 0x08, 0x0C, 0x7E, 0x0C, 0x08, 0x00, 0x00, // 09 - 0x00, 0x10, 0x10, 0x10, 0x7C, 0x38, 0x10, 0x00, // 0A - 0x08, 0x1C, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x00, // 0B - 0x38, 0x30, 0x28, 0x08, 0x08, 0x08, 0x3E, 0x00, // 0C - 0x00, 0x00, 0x12, 0x32, 0x7E, 0x30, 0x10, 0x00, // 0D - 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, // 0E - 0x3E, 0x7C, 0x7C, 0x3E, 0x3E, 0x7C, 0xF8, 0xF8, // 0F - 0x38, 0x30, 0x28, 0x04, 0x04, 0x04, 0x04, 0x00, // 10 - 0x7F, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x00, // 11 - 0x00, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x7F, // 12 - 0x7E, 0x81, 0x9D, 0xA1, 0xB9, 0x85, 0x85, 0xB9, // 13 - 0x00, 0x3C, 0x42, 0x5A, 0x5A, 0x42, 0x3C, 0x00, // 14 - 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11, // 15 - 0x00, 0x7F, 0x22, 0x72, 0x27, 0x22, 0x7F, 0x00, // 16 - 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, // 17 - 0x00, 0x01, 0x09, 0x0D, 0x7F, 0x0D, 0x09, 0x01, // 18 - 0x00, 0x90, 0xB0, 0xFE, 0xB0, 0x90, 0x00, 0x00, // 19 - 0x00, 0x08, 0x7C, 0x06, 0x7C, 0x08, 0x00, 0x00, // 1A - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // 1B - 0x7E, 0x81, 0xA1, 0xA1, 0xA1, 0xA1, 0xBD, 0x81, // 1C - 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0xA5, 0x81, // 1D - 0x7E, 0x81, 0x99, 0xA1, 0xA1, 0xA1, 0x99, 0x81, // 1E - 0x00, 0x10, 0x3E, 0x60, 0x3E, 0x10, 0x00, 0x00, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x00, // 21 - 0x77, 0x33, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x36, 0x36, 0xFE, 0x6C, 0xFE, 0xD8, 0xD8, 0x00, // 23 - 0x18, 0x3E, 0x6C, 0x3E, 0x1B, 0x1B, 0x7E, 0x18, // 24 - 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, // 25 - 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, // 26 - 0x1C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, // 28 - 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, // 29 - 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // 2A - 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x18, // 2C - 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, // 2E - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, // 2F - 0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 30 - 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, // 31 - 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, // 32 - 0xFC, 0x18, 0x30, 0x78, 0x0C, 0xCC, 0x78, 0x00, // 33 - 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, // 34 - 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, // 35 - 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, // 36 - 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, // 37 - 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, // 38 - 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, // 39 - 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, // 3A - 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, // 3B - 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, // 3C - 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00, // 3D - 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, // 3E - 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, // 3F - 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 40 - 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, // 41 - 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, // 42 - 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, // 43 - 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, // 44 - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, // 45 - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, // 46 - 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3C, 0x00, // 47 - 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, // 48 - 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, // 49 - 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, // 4A - 0xE6, 0x66, 0x6C, 0x70, 0x6C, 0x66, 0xE6, 0x00, // 4B - 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, // 4C - 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, // 4D - 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, // 4E - 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, // 4F - 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 50 - 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00, // 51 - 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, // 52 - 0x7C, 0xC6, 0xF0, 0x3C, 0x0E, 0xC6, 0x7C, 0x00, // 53 - 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, // 54 - 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, // 55 - 0xCC, 0xCC, 0xCC, 0x78, 0x78, 0x30, 0x30, 0x00, // 56 - 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, // 57 - 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00, // 58 - 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, // 59 - 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, // 5A - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5B - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 5C - 0x00, 0xFE, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, // 5D - 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, // 5E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // 5F - 0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C, // 60 - 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, // 61 - 0xE0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0xDC, 0x00, // 62 - 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, // 63 - 0x1C, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, // 64 - 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, // 65 - 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00, // 66 - 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, // 67 - 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, // 68 - 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0xFC, 0x00, // 69 - 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, // 6A - 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, // 6B - 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, // 6C - 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // 6D - 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, // 6E - 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, // 6F - 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 70 - 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, // 71 - 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00, // 72 - 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00, // 73 - 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00, // 74 - 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, // 75 - 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, // 76 - 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00, // 77 - 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, // 78 - 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, // 79 - 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, // 7A - 0x6C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, // 7B - 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, // 7C - 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, // 7D - 0x3C, 0x66, 0x66, 0x6C, 0x66, 0x66, 0x6C, 0xF0, // 7E - 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, // 7F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x00, // 80 - 0xFF, 0xFF, 0xDD, 0x8D, 0xDD, 0xC1, 0xFF, 0xFF, // 81 - 0xFF, 0xFF, 0xED, 0xCD, 0x81, 0xCD, 0xED, 0xFF, // 82 - 0x81, 0x7E, 0x46, 0x5A, 0x46, 0x5A, 0x46, 0x7E, // 83 - 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, // 84 - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // 85 - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, // 86 - 0xFF, 0xFF, 0xC3, 0xBD, 0xBD, 0x81, 0xFF, 0xFF, // 87 - 0xFF, 0xEF, 0xCF, 0x81, 0xCF, 0xEF, 0xFF, 0xFF, // 88 - 0xFF, 0xF7, 0xF3, 0x81, 0xF3, 0xF7, 0xFF, 0xFF, // 89 - 0xFF, 0xEF, 0xEF, 0xEF, 0x83, 0xC7, 0xEF, 0xFF, // 8A - 0xF7, 0xE3, 0xC1, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // 8B - 0xC7, 0xCF, 0xD7, 0xF7, 0xF7, 0xF7, 0xC1, 0xFF, // 8C - 0xFF, 0xFF, 0xED, 0xCD, 0x81, 0xCF, 0xEF, 0xFF, // 8D - 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 8E - 0xC1, 0x83, 0x83, 0xC1, 0xC1, 0x83, 0x07, 0x07, // 8F - 0xC7, 0xCF, 0xD7, 0xFB, 0xFB, 0xFB, 0xFB, 0xFF, // 90 - 0x80, 0xF7, 0xE3, 0xD5, 0xF7, 0xF7, 0xF7, 0xFF, // 91 - 0xFF, 0xF7, 0xF7, 0xF7, 0xD5, 0xE3, 0xF7, 0x80, // 92 - 0x81, 0x7E, 0x62, 0x5E, 0x46, 0x7A, 0x7A, 0x46, // 93 - 0xFF, 0xC3, 0xBD, 0xA5, 0xA5, 0xBD, 0xC3, 0xFF, // 94 - 0x77, 0xBB, 0xDD, 0xEE, 0x77, 0xBB, 0xDD, 0xEE, // 95 - 0xFF, 0x80, 0xDD, 0x8D, 0xD8, 0xDD, 0x80, 0xFF, // 96 - 0xEE, 0xDD, 0xBB, 0x77, 0xEE, 0xDD, 0xBB, 0x77, // 97 - 0xFF, 0xFE, 0xF6, 0xF2, 0x80, 0xF2, 0xF6, 0xFE, // 98 - 0xFF, 0x6F, 0x4F, 0x01, 0x4F, 0x6F, 0xFF, 0xFF, // 99 - 0xFF, 0xF7, 0x83, 0xF9, 0x83, 0xF7, 0xFF, 0xFF, // 9A - 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, // 9B - 0x81, 0x7E, 0x5E, 0x5E, 0x5E, 0x5E, 0x42, 0x7E, // 9C - 0x81, 0x7E, 0x46, 0x5A, 0x46, 0x5A, 0x5A, 0x7E, // 9D - 0x81, 0x7E, 0x66, 0x5E, 0x5E, 0x5E, 0x66, 0x7E, // 9E - 0xFF, 0xEF, 0xC1, 0x9F, 0xC1, 0xEF, 0xFF, 0xFF, // 9F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A0 - 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xFF, 0xCF, 0xFF, // A1 - 0x88, 0xCC, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A2 - 0xC9, 0xC9, 0x01, 0x93, 0x01, 0x27, 0x27, 0xFF, // A3 - 0xE7, 0xC1, 0x93, 0xC1, 0xE4, 0xE4, 0x81, 0xE7, // A4 - 0xFF, 0x39, 0x33, 0xE7, 0xCF, 0x99, 0x39, 0xFF, // A5 - 0xC7, 0x93, 0xC7, 0x89, 0x23, 0x33, 0x89, 0xFF, // A6 - 0xE3, 0xF3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A7 - 0xE7, 0xCF, 0x9F, 0x9F, 0x9F, 0xCF, 0xE7, 0xFF, // A8 - 0x9F, 0xCF, 0xE7, 0xE7, 0xE7, 0xCF, 0x9F, 0xFF, // A9 - 0xFF, 0x99, 0xC3, 0x00, 0xC3, 0x99, 0xFF, 0xFF, // AA - 0xFF, 0xCF, 0xCF, 0x03, 0xCF, 0xCF, 0xFF, 0xFF, // AB - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xF3, 0xE7, // AC - 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, // AD - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xCF, 0xFF, // AE - 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3F, 0x7F, 0xFF, // AF - 0x83, 0x39, 0x31, 0x21, 0x09, 0x19, 0x83, 0xFF, // B0 - 0xCF, 0x8F, 0xCF, 0xCF, 0xCF, 0xCF, 0x03, 0xFF, // B1 - 0x87, 0x33, 0xF3, 0xC7, 0x9F, 0x33, 0x03, 0xFF, // B2 - 0x03, 0xE7, 0xCF, 0x87, 0xF3, 0x33, 0x87, 0xFF, // B3 - 0xE3, 0xC3, 0x93, 0x33, 0x01, 0xF3, 0xE1, 0xFF, // B4 - 0x03, 0x3F, 0x07, 0xF3, 0xF3, 0x33, 0x87, 0xFF, // B5 - 0xC7, 0x9F, 0x3F, 0x07, 0x33, 0x33, 0x87, 0xFF, // B6 - 0x03, 0x33, 0xF3, 0xE7, 0xCF, 0xCF, 0xCF, 0xFF, // B7 - 0x87, 0x33, 0x33, 0x87, 0x33, 0x33, 0x87, 0xFF, // B8 - 0x87, 0x33, 0x33, 0x83, 0xF3, 0xE7, 0x8F, 0xFF, // B9 - 0xFF, 0xFF, 0xCF, 0xCF, 0xFF, 0xCF, 0xCF, 0xFF, // BA - 0xFF, 0xFF, 0xCF, 0xCF, 0xFF, 0xCF, 0xCF, 0x9F, // BB - 0xE7, 0xCF, 0x9F, 0x3F, 0x9F, 0xCF, 0xE7, 0xFF, // BC - 0xFF, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, // BD - 0x9F, 0xCF, 0xE7, 0xF3, 0xE7, 0xCF, 0x9F, 0xFF, // BE - 0x87, 0x33, 0xF3, 0xE7, 0xCF, 0xFF, 0xCF, 0xFF, // BF - 0x83, 0x39, 0x21, 0x21, 0x21, 0x3F, 0x87, 0xFF, // C0 - 0xCF, 0x87, 0x33, 0x33, 0x03, 0x33, 0x33, 0xFF, // C1 - 0x03, 0x99, 0x99, 0x83, 0x99, 0x99, 0x03, 0xFF, // C2 - 0xC3, 0x99, 0x3F, 0x3F, 0x3F, 0x99, 0xC3, 0xFF, // C3 - 0x07, 0x93, 0x99, 0x99, 0x99, 0x93, 0x07, 0xFF, // C4 - 0x01, 0x9D, 0x97, 0x87, 0x97, 0x9D, 0x01, 0xFF, // C5 - 0x01, 0x9D, 0x97, 0x87, 0x97, 0x9F, 0x0F, 0xFF, // C6 - 0xC3, 0x99, 0x3F, 0x3F, 0x31, 0x99, 0xC3, 0xFF, // C7 - 0x33, 0x33, 0x33, 0x03, 0x33, 0x33, 0x33, 0xFF, // C8 - 0x87, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0x87, 0xFF, // C9 - 0xE1, 0xF3, 0xF3, 0xF3, 0x33, 0x33, 0x87, 0xFF, // CA - 0x19, 0x99, 0x93, 0x8F, 0x93, 0x99, 0x19, 0xFF, // CB - 0x0F, 0x9F, 0x9F, 0x9F, 0x9D, 0x99, 0x01, 0xFF, // CC - 0x39, 0x11, 0x01, 0x29, 0x39, 0x39, 0x39, 0xFF, // CD - 0x39, 0x19, 0x09, 0x21, 0x31, 0x39, 0x39, 0xFF, // CE - 0xC7, 0x93, 0x39, 0x39, 0x39, 0x93, 0xC7, 0xFF, // CF - 0x03, 0x99, 0x99, 0x83, 0x9F, 0x9F, 0x0F, 0xFF, // D0 - 0x87, 0x33, 0x33, 0x33, 0x23, 0x87, 0xE3, 0xFF, // D1 - 0x03, 0x99, 0x99, 0x83, 0x93, 0x99, 0x19, 0xFF, // D2 - 0x83, 0x39, 0x0F, 0xC3, 0xF1, 0x39, 0x83, 0xFF, // D3 - 0x03, 0x4B, 0xCF, 0xCF, 0xCF, 0xCF, 0x87, 0xFF, // D4 - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x87, 0xFF, // D5 - 0x33, 0x33, 0x33, 0x87, 0x87, 0xCF, 0xCF, 0xFF, // D6 - 0x39, 0x39, 0x39, 0x29, 0x01, 0x11, 0x39, 0xFF, // D7 - 0x39, 0x39, 0x93, 0xC7, 0x93, 0x39, 0x39, 0xFF, // D8 - 0x33, 0x33, 0x33, 0x87, 0xCF, 0xCF, 0x87, 0xFF, // D9 - 0x01, 0x39, 0x73, 0xE7, 0xCD, 0x99, 0x01, 0xFF, // DA - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DB - 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, // DC - 0xFF, 0x01, 0xF9, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, // DD - 0xEF, 0xC7, 0x93, 0x39, 0xFF, 0xFF, 0xFF, 0xFF, // DE - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, // DF - 0xC3, 0xBD, 0x66, 0x5E, 0x5E, 0x66, 0xBD, 0xC3, // E0 - 0xFF, 0xFF, 0x87, 0xF3, 0x83, 0x33, 0x89, 0xFF, // E1 - 0x1F, 0x9F, 0x83, 0x99, 0x99, 0x99, 0x23, 0xFF, // E2 - 0xFF, 0xFF, 0x87, 0x33, 0x3F, 0x33, 0x87, 0xFF, // E3 - 0xE3, 0xF3, 0x83, 0x33, 0x33, 0x33, 0x89, 0xFF, // E4 - 0xFF, 0xFF, 0x87, 0x33, 0x03, 0x3F, 0x87, 0xFF, // E5 - 0xC7, 0x93, 0x9F, 0x0F, 0x9F, 0x9F, 0x0F, 0xFF, // E6 - 0xFF, 0xFF, 0x89, 0x33, 0x33, 0x83, 0xF3, 0x07, // E7 - 0x1F, 0x9F, 0x93, 0x89, 0x99, 0x99, 0x19, 0xFF, // E8 - 0xCF, 0xFF, 0x8F, 0xCF, 0xCF, 0xCF, 0x03, 0xFF, // E9 - 0xF3, 0xFF, 0xE3, 0xF3, 0xF3, 0x33, 0x33, 0x87, // EA - 0x1F, 0x9F, 0x99, 0x93, 0x87, 0x93, 0x19, 0xFF, // EB - 0x8F, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0x03, 0xFF, // EC - 0xFF, 0xFF, 0x33, 0x01, 0x01, 0x29, 0x39, 0xFF, // ED - 0xFF, 0xFF, 0x07, 0x33, 0x33, 0x33, 0x33, 0xFF, // EE - 0xFF, 0xFF, 0x87, 0x33, 0x33, 0x33, 0x87, 0xFF, // EF - 0xFF, 0xFF, 0x23, 0x99, 0x99, 0x83, 0x9F, 0x0F, // F0 - 0xFF, 0xFF, 0x89, 0x33, 0x33, 0x83, 0xF3, 0xE1, // F1 - 0xFF, 0xFF, 0x23, 0x89, 0x99, 0x9F, 0x0F, 0xFF, // F2 - 0xFF, 0xFF, 0x83, 0x3F, 0x87, 0xF3, 0x07, 0xFF, // F3 - 0xEF, 0xCF, 0x83, 0xCF, 0xCF, 0xCB, 0xE7, 0xFF, // F4 - 0xFF, 0xFF, 0x33, 0x33, 0x33, 0x33, 0x89, 0xFF, // F5 - 0xFF, 0xFF, 0x33, 0x33, 0x33, 0x87, 0xCF, 0xFF, // F6 - 0xFF, 0xFF, 0x39, 0x29, 0x01, 0x01, 0x93, 0xFF, // F7 - 0xFF, 0xFF, 0x39, 0x93, 0xC7, 0x93, 0x39, 0xFF, // F8 - 0xFF, 0xFF, 0x33, 0x33, 0x33, 0x83, 0xF3, 0x07, // F9 - 0xFF, 0xFF, 0x03, 0x67, 0xCF, 0x9B, 0x03, 0xFF, // FA - 0x93, 0xFF, 0x87, 0xF3, 0x83, 0x33, 0x89, 0xFF, // FB - 0x33, 0xFF, 0x87, 0x33, 0x33, 0x33, 0x87, 0xFF, // FC - 0x33, 0xFF, 0x33, 0x33, 0x33, 0x33, 0x89, 0xFF, // FD - 0xC3, 0x99, 0x99, 0x93, 0x99, 0x99, 0x93, 0x0F, // FE - 0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x00, // FF -}; -static const uint8_t _sdtx_font_z1013[2048] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 00 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 01 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 02 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 03 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 04 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 05 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 06 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 07 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 08 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 09 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0A - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0B - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0C - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0D - 0x00, 0x00, 0x18, 0x24, 0x24, 0x18, 0x24, 0x42, // 0E - 0xDB, 0xA5, 0x81, 0xFF, 0x24, 0x24, 0x24, 0x42, // 0F - 0x08, 0x34, 0x42, 0x81, 0x91, 0x69, 0x09, 0x31, // 10 - 0x42, 0x7E, 0x81, 0xFF, 0x00, 0x00, 0x00, 0x00, // 11 - 0x18, 0x24, 0x42, 0x99, 0xBD, 0x99, 0x42, 0x24, // 12 - 0x7E, 0x42, 0x99, 0xE7, 0x00, 0x00, 0x00, 0x00, // 13 - 0x18, 0xDB, 0xC3, 0x18, 0x99, 0xE7, 0x81, 0x42, // 14 - 0x18, 0x24, 0x18, 0xC3, 0xBD, 0x81, 0x81, 0x42, // 15 - 0x24, 0x7E, 0x81, 0xFF, 0x00, 0x00, 0x00, 0x00, // 16 - 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x3C, 0x7E, // 17 - 0xDB, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x7E, // 18 - 0x08, 0x3C, 0x7E, 0xFF, 0xFF, 0x6F, 0x0F, 0x3F, // 19 - 0x7E, 0x7E, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 1A - 0x18, 0x3C, 0x7E, 0xE7, 0xC3, 0xE7, 0x7E, 0x3C, // 1B - 0x7E, 0x7E, 0xFF, 0xE7, 0x00, 0x00, 0x00, 0x00, // 1C - 0x18, 0xDB, 0xC3, 0x18, 0x99, 0xFF, 0xFF, 0x7E, // 1D - 0x18, 0x3C, 0x18, 0xC3, 0xFF, 0xFF, 0xFF, 0x7E, // 1E - 0x3C, 0x3C, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x00, // 21 - 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x24, 0x7E, 0x24, 0x24, 0x24, 0x7E, 0x24, 0x00, // 23 - 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, // 24 - 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, // 25 - 0x10, 0x28, 0x28, 0x30, 0x54, 0x48, 0x34, 0x00, // 26 - 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // 28 - 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, // 29 - 0x00, 0x10, 0x54, 0x38, 0x54, 0x10, 0x00, 0x00, // 2A - 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, // 2C - 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, // 2E - 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, // 2F - 0x38, 0x44, 0x44, 0x54, 0x44, 0x44, 0x38, 0x00, // 30 - 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, // 31 - 0x38, 0x44, 0x04, 0x08, 0x10, 0x20, 0x7C, 0x00, // 32 - 0x7C, 0x08, 0x10, 0x08, 0x04, 0x44, 0x38, 0x00, // 33 - 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, // 34 - 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, // 35 - 0x18, 0x20, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, // 36 - 0x7C, 0x04, 0x08, 0x10, 0x20, 0x20, 0x20, 0x00, // 37 - 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, // 38 - 0x38, 0x44, 0x44, 0x3C, 0x04, 0x08, 0x30, 0x00, // 39 - 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, 0x00, // 3A - 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x20, 0x00, // 3B - 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, // 3C - 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, // 3D - 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, // 3E - 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, // 3F - 0x38, 0x44, 0x5C, 0x54, 0x5C, 0x40, 0x3C, 0x00, // 40 - 0x38, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, // 41 - 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, // 42 - 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, // 43 - 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, // 44 - 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7C, 0x00, // 45 - 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00, // 46 - 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x3C, 0x00, // 47 - 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, // 48 - 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, // 49 - 0x1C, 0x08, 0x08, 0x08, 0x08, 0x48, 0x30, 0x00, // 4A - 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, // 4B - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, // 4C - 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, // 4D - 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, // 4E - 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, // 4F - 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, // 50 - 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, // 51 - 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, // 52 - 0x3C, 0x40, 0x40, 0x38, 0x04, 0x04, 0x78, 0x00, // 53 - 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, // 54 - 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, // 55 - 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, // 56 - 0x44, 0x44, 0x44, 0x54, 0x54, 0x6C, 0x44, 0x00, // 57 - 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, // 58 - 0x44, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00, // 59 - 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, // 5A - 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, // 5B - 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, // 5C - 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, // 5D - 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, // 5E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, // 5F - 0x00, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, // 60 - 0x00, 0x00, 0x34, 0x4C, 0x44, 0x44, 0x3A, 0x00, // 61 - 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x78, 0x00, // 62 - 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, // 63 - 0x04, 0x04, 0x34, 0x4C, 0x44, 0x44, 0x3A, 0x00, // 64 - 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, // 65 - 0x08, 0x10, 0x38, 0x10, 0x10, 0x10, 0x10, 0x00, // 66 - 0x00, 0x00, 0x34, 0x4C, 0x44, 0x3C, 0x04, 0x38, // 67 - 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, // 68 - 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x08, 0x00, // 69 - 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, // 6A - 0x40, 0x40, 0x48, 0x50, 0x70, 0x48, 0x44, 0x00, // 6B - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x00, // 6C - 0x00, 0x00, 0x68, 0x54, 0x54, 0x54, 0x54, 0x00, // 6D - 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, // 6E - 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, // 6F - 0x00, 0x00, 0x58, 0x64, 0x44, 0x78, 0x40, 0x40, // 70 - 0x00, 0x00, 0x34, 0x4C, 0x44, 0x3C, 0x04, 0x04, // 71 - 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, // 72 - 0x00, 0x00, 0x38, 0x40, 0x38, 0x04, 0x78, 0x00, // 73 - 0x10, 0x10, 0x38, 0x10, 0x10, 0x10, 0x08, 0x00, // 74 - 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, // 75 - 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, // 76 - 0x00, 0x00, 0x54, 0x54, 0x54, 0x54, 0x28, 0x00, // 77 - 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, // 78 - 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, // 79 - 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, // 7A - 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, // 7B - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, // 7C - 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, // 7D - 0x00, 0x00, 0x00, 0x32, 0x4C, 0x00, 0x00, 0x00, // 7E - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7F - 0xC0, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0xC0, // 80 - 0x03, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x03, // 81 - 0x81, 0x81, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00, // 82 - 0x00, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x81, 0x81, // 83 - 0x10, 0x10, 0x20, 0xC0, 0x00, 0x00, 0x00, 0x00, // 84 - 0x08, 0x08, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, // 85 - 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x08, 0x08, // 86 - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x20, 0x10, 0x10, // 87 - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF, // 88 - 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 89 - 0x00, 0x10, 0x28, 0x44, 0x82, 0x44, 0x28, 0x10, // 8A - 0xFF, 0xEF, 0xC7, 0x83, 0x01, 0x83, 0xC7, 0xEF, // 8B - 0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C, // 8C - 0xC3, 0x81, 0x00, 0x00, 0x00, 0x00, 0x81, 0xC3, // 8D - 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, // 8E - 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, // 8F - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, // 90 - 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, // 91 - 0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x30, 0xC0, // 92 - 0x03, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, // 93 - 0x03, 0x0C, 0x30, 0xC0, 0xC0, 0x30, 0x0C, 0x03, // 94 - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x30, 0x0C, 0x03, // 95 - 0xC0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00, // 96 - 0xC0, 0x30, 0x0C, 0x03, 0x03, 0x0C, 0x30, 0xC0, // 97 - 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, // 98 - 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, // 99 - 0x81, 0x81, 0x42, 0x42, 0x24, 0x24, 0x18, 0x18, // 9A - 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, // 9B - 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, // 9C - 0x18, 0x18, 0x24, 0x24, 0x42, 0x42, 0x81, 0x81, // 9D - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9E - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 9F - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, // A0 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // A1 - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, // A2 - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, // A3 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, // A4 - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, // A5 - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, // A6 - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, // A7 - 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18, // A8 - 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, // A9 - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00, // AA - 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x18, 0x07, // AB - 0x01, 0x01, 0x01, 0x02, 0x02, 0x04, 0x18, 0xE0, // AC - 0xE0, 0x18, 0x04, 0x02, 0x02, 0x01, 0x01, 0x01, // AD - 0x07, 0x18, 0x20, 0x40, 0x40, 0x80, 0x80, 0x80, // AE - 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81, // AF - 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // B0 - 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // B1 - 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // B2 - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // B3 - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // B4 - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // B5 - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // B6 - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // B7 - 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // B8 - 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, // B9 - 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, // BA - 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, // BB - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, // BC - 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, // BD - 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, // BE - 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, // BF - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // C0 - 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // C1 - 0xFF, 0x80, 0x80, 0x9C, 0x9C, 0x9C, 0x80, 0x80, // C2 - 0xFF, 0xFF, 0xFF, 0xE3, 0xE3, 0xE3, 0xFF, 0xFF, // C3 - 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x3C, 0x7E, 0xFF, // C4 - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, // C5 - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // C6 - 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, // C7 - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, // C8 - 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, // C9 - 0x38, 0x10, 0x92, 0xFE, 0x92, 0x10, 0x38, 0x7C, // CA - 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, // CB - 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x7C, 0x10, 0x7C, // CC - 0xE7, 0xE7, 0x42, 0xFF, 0xFF, 0x42, 0xE7, 0xE7, // CD - 0xDB, 0xFF, 0xDB, 0x18, 0x18, 0xDB, 0xFF, 0xDB, // CE - 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, // CF - 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D0 - 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D1 - 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D2 - 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D3 - 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, // D4 - 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, // D5 - 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, // D6 - 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, // D7 - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, // D8 - 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, // D9 - 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, // DA - 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, // DB - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, // DC - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, // DD - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, // DE - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, // DF - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, // E0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, // E1 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // E2 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, // E3 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, // E4 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, // E5 - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, // E6 - 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // E7 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // E8 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, // E9 - 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, // EA - 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EB - 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EC - 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ED - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EE - 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EF - 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F0 - 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F1 - 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, // F2 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, // F3 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // F4 - 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // F5 - 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, // F6 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, // F7 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // F8 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // F9 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // FA - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // FB - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FC - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FD - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FE - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FF -}; -static const uint8_t _sdtx_font_cpc[2048] = { - 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, // 00 - 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 01 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, // 02 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, // 03 - 0x0C, 0x18, 0x30, 0x7E, 0x0C, 0x18, 0x30, 0x00, // 04 - 0xFF, 0xC3, 0xE7, 0xDB, 0xDB, 0xE7, 0xC3, 0xFF, // 05 - 0x00, 0x01, 0x03, 0x06, 0xCC, 0x78, 0x30, 0x00, // 06 - 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0x24, 0xE7, 0x00, // 07 - 0x00, 0x00, 0x30, 0x60, 0xFF, 0x60, 0x30, 0x00, // 08 - 0x00, 0x00, 0x0C, 0x06, 0xFF, 0x06, 0x0C, 0x00, // 09 - 0x18, 0x18, 0x18, 0x18, 0xDB, 0x7E, 0x3C, 0x18, // 0A - 0x18, 0x3C, 0x7E, 0xDB, 0x18, 0x18, 0x18, 0x18, // 0B - 0x18, 0x5A, 0x3C, 0x99, 0xDB, 0x7E, 0x3C, 0x18, // 0C - 0x00, 0x03, 0x33, 0x63, 0xFE, 0x60, 0x30, 0x00, // 0D - 0x3C, 0x66, 0xFF, 0xDB, 0xDB, 0xFF, 0x66, 0x3C, // 0E - 0x3C, 0x66, 0xC3, 0xDB, 0xDB, 0xC3, 0x66, 0x3C, // 0F - 0xFF, 0xC3, 0xC3, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, // 10 - 0x3C, 0x7E, 0xDB, 0xDB, 0xDF, 0xC3, 0x66, 0x3C, // 11 - 0x3C, 0x66, 0xC3, 0xDF, 0xDB, 0xDB, 0x7E, 0x3C, // 12 - 0x3C, 0x66, 0xC3, 0xFB, 0xDB, 0xDB, 0x7E, 0x3C, // 13 - 0x3C, 0x7E, 0xDB, 0xDB, 0xFB, 0xC3, 0x66, 0x3C, // 14 - 0x00, 0x01, 0x33, 0x1E, 0xCE, 0x7B, 0x31, 0x00, // 15 - 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xE7, // 16 - 0x03, 0x03, 0x03, 0xFF, 0x03, 0x03, 0x03, 0x00, // 17 - 0xFF, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x66, 0xFF, // 18 - 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x3C, 0x18, 0x18, // 19 - 0x3C, 0x66, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // 1A - 0x3C, 0x66, 0xC3, 0xFF, 0xC3, 0xC3, 0x66, 0x3C, // 1B - 0xFF, 0xDB, 0xDB, 0xDB, 0xFB, 0xC3, 0xC3, 0xFF, // 1C - 0xFF, 0xC3, 0xC3, 0xFB, 0xDB, 0xDB, 0xDB, 0xFF, // 1D - 0xFF, 0xC3, 0xC3, 0xDF, 0xDB, 0xDB, 0xDB, 0xFF, // 1E - 0xFF, 0xDB, 0xDB, 0xDB, 0xDF, 0xC3, 0xC3, 0xFF, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, // 21 - 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, // 23 - 0x18, 0x3E, 0x58, 0x3C, 0x1A, 0x7C, 0x18, 0x00, // 24 - 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, // 25 - 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, // 26 - 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, // 28 - 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, // 29 - 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // 2A - 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, // 2C - 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // 2E - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, // 2F - 0x7C, 0xC6, 0xCE, 0xD6, 0xE6, 0xC6, 0x7C, 0x00, // 30 - 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, // 31 - 0x3C, 0x66, 0x06, 0x3C, 0x60, 0x66, 0x7E, 0x00, // 32 - 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, // 33 - 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, // 34 - 0x7E, 0x62, 0x60, 0x7C, 0x06, 0x66, 0x3C, 0x00, // 35 - 0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, // 36 - 0x7E, 0x66, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x00, // 37 - 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // 38 - 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, // 39 - 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, // 3A - 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, // 3B - 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, // 3C - 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, // 3D - 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, // 3E - 0x3C, 0x66, 0x66, 0x0C, 0x18, 0x00, 0x18, 0x00, // 3F - 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x7C, 0x00, // 40 - 0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 41 - 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, // 42 - 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, // 43 - 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, // 44 - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, // 45 - 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, // 46 - 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00, // 47 - 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // 48 - 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, // 49 - 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, // 4A - 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, // 4B - 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, // 4C - 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, // 4D - 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, // 4E - 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, // 4F - 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 50 - 0x38, 0x6C, 0xC6, 0xC6, 0xDA, 0xCC, 0x76, 0x00, // 51 - 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, // 52 - 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, // 53 - 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 54 - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 55 - 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 56 - 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, // 57 - 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0xC6, 0x00, // 58 - 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00, // 59 - 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, // 5A - 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, // 5B - 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, // 5C - 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, // 5D - 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, // 5E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // 5F - 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, // 60 - 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, // 61 - 0xE0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0xDC, 0x00, // 62 - 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, // 63 - 0x1C, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, // 64 - 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, // 65 - 0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, // 66 - 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C, // 67 - 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, // 68 - 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, // 69 - 0x06, 0x00, 0x0E, 0x06, 0x06, 0x66, 0x66, 0x3C, // 6A - 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, // 6B - 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 6C - 0x00, 0x00, 0x6C, 0xFE, 0xD6, 0xD6, 0xC6, 0x00, // 6D - 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00, // 6E - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // 6F - 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 70 - 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, // 71 - 0x00, 0x00, 0xDC, 0x76, 0x60, 0x60, 0xF0, 0x00, // 72 - 0x00, 0x00, 0x3C, 0x60, 0x3C, 0x06, 0x7C, 0x00, // 73 - 0x30, 0x30, 0x7C, 0x30, 0x30, 0x36, 0x1C, 0x00, // 74 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, // 75 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 76 - 0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, // 77 - 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, // 78 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x7C, // 79 - 0x00, 0x00, 0x7E, 0x4C, 0x18, 0x32, 0x7E, 0x00, // 7A - 0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0x00, // 7B - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 7C - 0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0x00, // 7D - 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7E - 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, // 7F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // 81 - 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // 82 - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 83 - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // 84 - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // 85 - 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, // 86 - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, // 87 - 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // 88 - 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // 89 - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 8A - 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, // 8B - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 8C - 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, // 8D - 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, // 8E - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8F - 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, // 90 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, // 91 - 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x00, // 92 - 0x18, 0x18, 0x18, 0x1F, 0x0F, 0x00, 0x00, 0x00, // 93 - 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, // 94 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 95 - 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x18, 0x18, 0x18, // 96 - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, // 97 - 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x00, // 98 - 0x18, 0x18, 0x18, 0xF8, 0xF0, 0x00, 0x00, 0x00, // 99 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 9A - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 9B - 0x00, 0x00, 0x00, 0xF0, 0xF8, 0x18, 0x18, 0x18, // 9C - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, // 9D - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, // 9E - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, // 9F - 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, // A0 - 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, // A1 - 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // A2 - 0x3C, 0x66, 0x60, 0xF8, 0x60, 0x66, 0xFE, 0x00, // A3 - 0x38, 0x44, 0xBA, 0xA2, 0xBA, 0x44, 0x38, 0x00, // A4 - 0x7E, 0xF4, 0xF4, 0x74, 0x34, 0x34, 0x34, 0x00, // A5 - 0x1E, 0x30, 0x38, 0x6C, 0x38, 0x18, 0xF0, 0x00, // A6 - 0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, // A7 - 0x40, 0xC0, 0x44, 0x4C, 0x54, 0x1E, 0x04, 0x00, // A8 - 0x40, 0xC0, 0x4C, 0x52, 0x44, 0x08, 0x1E, 0x00, // A9 - 0xE0, 0x10, 0x62, 0x16, 0xEA, 0x0F, 0x02, 0x00, // AA - 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x7E, 0x00, // AB - 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, // AC - 0x00, 0x00, 0x00, 0x7E, 0x06, 0x06, 0x00, 0x00, // AD - 0x18, 0x00, 0x18, 0x30, 0x66, 0x66, 0x3C, 0x00, // AE - 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // AF - 0x00, 0x00, 0x73, 0xDE, 0xCC, 0xDE, 0x73, 0x00, // B0 - 0x7C, 0xC6, 0xC6, 0xFC, 0xC6, 0xC6, 0xF8, 0xC0, // B1 - 0x00, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // B2 - 0x3C, 0x60, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00, // B3 - 0x00, 0x00, 0x1E, 0x30, 0x7C, 0x30, 0x1E, 0x00, // B4 - 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00, // B5 - 0x00, 0xC0, 0x60, 0x30, 0x38, 0x6C, 0xC6, 0x00, // B6 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, // B7 - 0x00, 0x00, 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x00, // B8 - 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0x70, 0x00, // B9 - 0x03, 0x06, 0x0C, 0x3C, 0x66, 0x3C, 0x60, 0xC0, // BA - 0x03, 0x06, 0x0C, 0x66, 0x66, 0x3C, 0x60, 0xC0, // BB - 0x00, 0xE6, 0x3C, 0x18, 0x38, 0x6C, 0xC7, 0x00, // BC - 0x00, 0x00, 0x66, 0xC3, 0xDB, 0xDB, 0x7E, 0x00, // BD - 0xFE, 0xC6, 0x60, 0x30, 0x60, 0xC6, 0xFE, 0x00, // BE - 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x6C, 0xEE, 0x00, // BF - 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, // C0 - 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, // C1 - 0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x18, // C2 - 0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, // C3 - 0x18, 0x3C, 0x66, 0xC3, 0x81, 0x00, 0x00, 0x00, // C4 - 0x18, 0x0C, 0x06, 0x03, 0x03, 0x06, 0x0C, 0x18, // C5 - 0x00, 0x00, 0x00, 0x81, 0xC3, 0x66, 0x3C, 0x18, // C6 - 0x18, 0x30, 0x60, 0xC0, 0xC0, 0x60, 0x30, 0x18, // C7 - 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, // C8 - 0x18, 0x0C, 0x06, 0x83, 0xC1, 0x60, 0x30, 0x18, // C9 - 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0x66, 0x3C, 0x18, // CA - 0xC3, 0xE7, 0x7E, 0x3C, 0x3C, 0x7E, 0xE7, 0xC3, // CB - 0x03, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xC0, // CC - 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, // CD - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // CE - 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, // CF - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D0 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // D1 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // D2 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // D3 - 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, // D4 - 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, // D5 - 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, // D6 - 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, // D7 - 0xAA, 0x55, 0xAA, 0x55, 0x00, 0x00, 0x00, 0x00, // D8 - 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0A, 0x05, // D9 - 0x00, 0x00, 0x00, 0x00, 0xAA, 0x55, 0xAA, 0x55, // DA - 0xA0, 0x50, 0xA0, 0x50, 0xA0, 0x50, 0xA0, 0x50, // DB - 0xAA, 0x54, 0xA8, 0x50, 0xA0, 0x40, 0x80, 0x00, // DC - 0xAA, 0x55, 0x2A, 0x15, 0x0A, 0x05, 0x02, 0x01, // DD - 0x01, 0x02, 0x05, 0x0A, 0x15, 0x2A, 0x55, 0xAA, // DE - 0x00, 0x80, 0x40, 0xA0, 0x50, 0xA8, 0x54, 0xAA, // DF - 0x7E, 0xFF, 0x99, 0xFF, 0xBD, 0xC3, 0xFF, 0x7E, // E0 - 0x7E, 0xFF, 0x99, 0xFF, 0xC3, 0xBD, 0xFF, 0x7E, // E1 - 0x38, 0x38, 0xFE, 0xFE, 0xFE, 0x10, 0x38, 0x00, // E2 - 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, // E3 - 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, // E4 - 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x10, 0x38, 0x00, // E5 - 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0x66, 0x3C, 0x00, // E6 - 0x00, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x00, // E7 - 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x00, // E8 - 0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x00, // E9 - 0x0F, 0x07, 0x0D, 0x78, 0xCC, 0xCC, 0xCC, 0x78, // EA - 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, // EB - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x7C, 0x38, // EC - 0x18, 0x1C, 0x1E, 0x1B, 0x18, 0x78, 0xF8, 0x70, // ED - 0x99, 0x5A, 0x24, 0xC3, 0xC3, 0x24, 0x5A, 0x99, // EE - 0x10, 0x38, 0x38, 0x38, 0x38, 0x38, 0x7C, 0xD6, // EF - 0x18, 0x3C, 0x7E, 0xFF, 0x18, 0x18, 0x18, 0x18, // F0 - 0x18, 0x18, 0x18, 0x18, 0xFF, 0x7E, 0x3C, 0x18, // F1 - 0x10, 0x30, 0x70, 0xFF, 0xFF, 0x70, 0x30, 0x10, // F2 - 0x08, 0x0C, 0x0E, 0xFF, 0xFF, 0x0E, 0x0C, 0x08, // F3 - 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, // F4 - 0x00, 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, // F5 - 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, // F6 - 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, // F7 - 0x38, 0x38, 0x92, 0x7C, 0x10, 0x28, 0x28, 0x28, // F8 - 0x38, 0x38, 0x10, 0xFE, 0x10, 0x28, 0x44, 0x82, // F9 - 0x38, 0x38, 0x12, 0x7C, 0x90, 0x28, 0x24, 0x22, // FA - 0x38, 0x38, 0x90, 0x7C, 0x12, 0x28, 0x48, 0x88, // FB - 0x00, 0x3C, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, // FC - 0x3C, 0xFF, 0xFF, 0x18, 0x0C, 0x18, 0x30, 0x18, // FD - 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, // FE - 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, // FF -}; -static const uint8_t _sdtx_font_c64[2048] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 00 - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // 01 - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 02 - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 03 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // 04 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 05 - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // 06 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 07 - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0x33, 0x33, // 08 - 0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99, 0x33, 0x66, // 09 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 0A - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, // 0B - 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // 0C - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, // 0D - 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, // 0E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // 0F - 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18, // 10 - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 11 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, // 12 - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, // 13 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 14 - 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, // 15 - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, // 16 - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 17 - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, // 18 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // 19 - 0x01, 0x03, 0x06, 0x6C, 0x78, 0x70, 0x60, 0x00, // 1A - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // 1B - 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // 1C - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00, // 1D - 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // 1E - 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00, // 21 - 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, 0x00, // 23 - 0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00, // 24 - 0x62, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x46, 0x00, // 25 - 0x3C, 0x66, 0x3C, 0x38, 0x67, 0x66, 0x3F, 0x00, // 26 - 0x06, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, // 28 - 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, // 29 - 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // 2A - 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, // 2C - 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // 2E - 0x00, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, // 2F - 0x3C, 0x66, 0x6E, 0x76, 0x66, 0x66, 0x3C, 0x00, // 30 - 0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7E, 0x00, // 31 - 0x3C, 0x66, 0x06, 0x0C, 0x30, 0x60, 0x7E, 0x00, // 32 - 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, // 33 - 0x06, 0x0E, 0x1E, 0x66, 0x7F, 0x06, 0x06, 0x00, // 34 - 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, // 35 - 0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, // 36 - 0x7E, 0x66, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, // 37 - 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // 38 - 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, // 39 - 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, // 3A - 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, // 3B - 0x0E, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0E, 0x00, // 3C - 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, // 3D - 0x70, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x70, 0x00, // 3E - 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x00, 0x18, 0x00, // 3F - 0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, // 40 - 0x18, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // 41 - 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, // 42 - 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, // 43 - 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, // 44 - 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7E, 0x00, // 45 - 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00, // 46 - 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00, // 47 - 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // 48 - 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 49 - 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, // 4A - 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, // 4B - 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, // 4C - 0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00, // 4D - 0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00, // 4E - 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 4F - 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, // 50 - 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x0E, 0x00, // 51 - 0x7C, 0x66, 0x66, 0x7C, 0x78, 0x6C, 0x66, 0x00, // 52 - 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, // 53 - 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 54 - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // 55 - 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 56 - 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00, // 57 - 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // 58 - 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // 59 - 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, // 5A - 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, // 5B - 0x0C, 0x12, 0x30, 0x7C, 0x30, 0x62, 0xFC, 0x00, // 5C - 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, // 5D - 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, // 5E - 0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00, // 5F - 0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, // 60 - 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, // 61 - 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // 62 - 0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00, // 63 - 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // 64 - 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, // 65 - 0x00, 0x0E, 0x18, 0x3E, 0x18, 0x18, 0x18, 0x00, // 66 - 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C, // 67 - 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x00, // 68 - 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3C, 0x00, // 69 - 0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3C, // 6A - 0x00, 0x60, 0x60, 0x6C, 0x78, 0x6C, 0x66, 0x00, // 6B - 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // 6C - 0x00, 0x00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0x00, // 6D - 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, // 6E - 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // 6F - 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, // 70 - 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06, // 71 - 0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00, // 72 - 0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00, // 73 - 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x0E, 0x00, // 74 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, // 75 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // 76 - 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x3E, 0x36, 0x00, // 77 - 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // 78 - 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x0C, 0x78, // 79 - 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, // 7A - 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, // 7B - 0x0C, 0x12, 0x30, 0x7C, 0x30, 0x62, 0xFC, 0x00, // 7C - 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, // 7D - 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, // 7E - 0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00, // 7F - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 80 - 0x08, 0x1C, 0x3E, 0x7F, 0x7F, 0x1C, 0x3E, 0x00, // 81 - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 82 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 83 - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 84 - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, // 85 - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, // 86 - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // 87 - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, // 88 - 0x00, 0x00, 0x00, 0xE0, 0xF0, 0x38, 0x18, 0x18, // 89 - 0x18, 0x18, 0x1C, 0x0F, 0x07, 0x00, 0x00, 0x00, // 8A - 0x18, 0x18, 0x38, 0xF0, 0xE0, 0x00, 0x00, 0x00, // 8B - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, // 8C - 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, // 8D - 0x03, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xC0, // 8E - 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 8F - 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 90 - 0x00, 0x3C, 0x7E, 0x7E, 0x7E, 0x7E, 0x3C, 0x00, // 91 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, // 92 - 0x36, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, // 93 - 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, // 94 - 0x00, 0x00, 0x00, 0x07, 0x0F, 0x1C, 0x18, 0x18, // 95 - 0xC3, 0xE7, 0x7E, 0x3C, 0x3C, 0x7E, 0xE7, 0xC3, // 96 - 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x3C, 0x00, // 97 - 0x18, 0x18, 0x66, 0x66, 0x18, 0x18, 0x3C, 0x00, // 98 - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, // 99 - 0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00, // 9A - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, // 9B - 0xC0, 0xC0, 0x30, 0x30, 0xC0, 0xC0, 0x30, 0x30, // 9C - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 9D - 0x00, 0x00, 0x03, 0x3E, 0x76, 0x36, 0x36, 0x00, // 9E - 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, // 9F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // A0 - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // A1 - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // A2 - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // A3 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // A4 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // A5 - 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, // A6 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // A7 - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0x33, 0x33, // A8 - 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, // A9 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // AA - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, // AB - 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // AC - 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, // AD - 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, // AE - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // AF - 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18, // B0 - 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, // B1 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, // B2 - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, // B3 - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // B4 - 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, // B5 - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, // B6 - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B7 - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, // B8 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // B9 - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xFF, // BA - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // BB - 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // BC - 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00, // BD - 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // BE - 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // BF - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // C0 - 0xF7, 0xE3, 0xC1, 0x80, 0x80, 0xE3, 0xC1, 0xFF, // C1 - 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, // C2 - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // C3 - 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // C4 - 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C5 - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, // C6 - 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, // C7 - 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, // C8 - 0xFF, 0xFF, 0xFF, 0x1F, 0x0F, 0xC7, 0xE7, 0xE7, // C9 - 0xE7, 0xE7, 0xE3, 0xF0, 0xF8, 0xFF, 0xFF, 0xFF, // CA - 0xE7, 0xE7, 0xC7, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, // CB - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, // CC - 0x3F, 0x1F, 0x8F, 0xC7, 0xE3, 0xF1, 0xF8, 0xFC, // CD - 0xFC, 0xF8, 0xF1, 0xE3, 0xC7, 0x8F, 0x1F, 0x3F, // CE - 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // CF - 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, // D0 - 0xFF, 0xC3, 0x81, 0x81, 0x81, 0x81, 0xC3, 0xFF, // D1 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, // D2 - 0xC9, 0x80, 0x80, 0x80, 0xC1, 0xE3, 0xF7, 0xFF, // D3 - 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, // D4 - 0xFF, 0xFF, 0xFF, 0xF8, 0xF0, 0xE3, 0xE7, 0xE7, // D5 - 0x3C, 0x18, 0x81, 0xC3, 0xC3, 0x81, 0x18, 0x3C, // D6 - 0xFF, 0xC3, 0x81, 0x99, 0x99, 0x81, 0xC3, 0xFF, // D7 - 0xE7, 0xE7, 0x99, 0x99, 0xE7, 0xE7, 0xC3, 0xFF, // D8 - 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, // D9 - 0xF7, 0xE3, 0xC1, 0x80, 0xC1, 0xE3, 0xF7, 0xFF, // DA - 0xE7, 0xE7, 0xE7, 0x00, 0x00, 0xE7, 0xE7, 0xE7, // DB - 0x3F, 0x3F, 0xCF, 0xCF, 0x3F, 0x3F, 0xCF, 0xCF, // DC - 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, // DD - 0xFF, 0xFF, 0xFC, 0xC1, 0x89, 0xC9, 0xC9, 0xFF, // DE - 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, // DF - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // E0 - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // E1 - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // E2 - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // E3 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, // E4 - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // E5 - 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, // E6 - 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, // E7 - 0xFF, 0xFF, 0xFF, 0xFF, 0x33, 0x33, 0xCC, 0xCC, // E8 - 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, // E9 - 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, // EA - 0xE7, 0xE7, 0xE7, 0xE0, 0xE0, 0xE7, 0xE7, 0xE7, // EB - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, // EC - 0xE7, 0xE7, 0xE7, 0xE0, 0xE0, 0xFF, 0xFF, 0xFF, // ED - 0xFF, 0xFF, 0xFF, 0x07, 0x07, 0xE7, 0xE7, 0xE7, // EE - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, // EF - 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0xE7, 0xE7, 0xE7, // F0 - 0xE7, 0xE7, 0xE7, 0x00, 0x00, 0xFF, 0xFF, 0xFF, // F1 - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xE7, 0xE7, 0xE7, // F2 - 0xE7, 0xE7, 0xE7, 0x07, 0x07, 0xE7, 0xE7, 0xE7, // F3 - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // F4 - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, // F5 - 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, // F6 - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // F7 - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // F8 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, // F9 - 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, // FA - 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, // FB - 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, // FC - 0xE7, 0xE7, 0xE7, 0x07, 0x07, 0xFF, 0xFF, 0xFF, // FD - 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, // FE - 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, // FF -}; -static const uint8_t _sdtx_font_oric[2048] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 00 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 01 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 02 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 03 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 04 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 05 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 06 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 07 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 08 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 09 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0A - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0C - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 10 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 11 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 12 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 13 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 14 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 15 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 17 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 18 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 19 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1A - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1C - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 - 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, // 21 - 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 - 0x14, 0x14, 0x3E, 0x14, 0x3E, 0x14, 0x14, 0x00, // 23 - 0x08, 0x1E, 0x28, 0x1C, 0x0A, 0x3C, 0x08, 0x00, // 24 - 0x30, 0x32, 0x04, 0x08, 0x10, 0x26, 0x06, 0x00, // 25 - 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, // 26 - 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 - 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // 28 - 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, // 29 - 0x08, 0x2A, 0x1C, 0x08, 0x1C, 0x2A, 0x08, 0x00, // 2A - 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, // 2B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, // 2C - 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // 2D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // 2E - 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // 2F - 0x1C, 0x22, 0x26, 0x2A, 0x32, 0x22, 0x1C, 0x00, // 30 - 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 31 - 0x1C, 0x22, 0x02, 0x04, 0x08, 0x10, 0x3E, 0x00, // 32 - 0x3E, 0x02, 0x04, 0x0C, 0x02, 0x22, 0x1C, 0x00, // 33 - 0x04, 0x0C, 0x14, 0x24, 0x3E, 0x04, 0x04, 0x00, // 34 - 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, // 35 - 0x0C, 0x10, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, // 36 - 0x3E, 0x02, 0x04, 0x08, 0x10, 0x10, 0x10, 0x00, // 37 - 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, // 38 - 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x04, 0x18, 0x00, // 39 - 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, // 3A - 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, // 3B - 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, // 3C - 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // 3D - 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, // 3E - 0x1C, 0x22, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, // 3F - 0x1C, 0x22, 0x2A, 0x2E, 0x2C, 0x20, 0x1E, 0x00, // 40 - 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, // 41 - 0x3C, 0x22, 0x22, 0x3C, 0x22, 0x22, 0x3C, 0x00, // 42 - 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, // 43 - 0x3C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3C, 0x00, // 44 - 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, // 45 - 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, // 46 - 0x1E, 0x20, 0x20, 0x20, 0x26, 0x22, 0x1E, 0x00, // 47 - 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, // 48 - 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 49 - 0x02, 0x02, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00, // 4A - 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, // 4B - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, // 4C - 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, // 4D - 0x22, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x00, // 4E - 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, // 4F - 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, // 50 - 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, // 51 - 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, // 52 - 0x1C, 0x22, 0x20, 0x1C, 0x02, 0x22, 0x1C, 0x00, // 53 - 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, // 54 - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, // 55 - 0x22, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, // 56 - 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, // 57 - 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, // 58 - 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, // 59 - 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, // 5A - 0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00, // 5B - 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, // 5C - 0x3C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3C, 0x00, // 5D - 0x08, 0x14, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, // 5E - 0x0E, 0x11, 0x3C, 0x10, 0x3C, 0x11, 0x0E, 0x00, // 5F - 0x0C, 0x12, 0x2D, 0x29, 0x29, 0x2D, 0x12, 0x0C, // 60 - 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, // 61 - 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, // 62 - 0x00, 0x00, 0x1E, 0x20, 0x20, 0x20, 0x1E, 0x00, // 63 - 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, // 64 - 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1E, 0x00, // 65 - 0x0C, 0x12, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x00, // 66 - 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x1C, // 67 - 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, // 68 - 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, // 69 - 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x24, 0x18, // 6A - 0x20, 0x20, 0x22, 0x24, 0x38, 0x24, 0x22, 0x00, // 6B - 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 6C - 0x00, 0x00, 0x36, 0x2A, 0x2A, 0x2A, 0x22, 0x00, // 6D - 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, // 6E - 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, // 6F - 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, // 70 - 0x00, 0x00, 0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, // 71 - 0x00, 0x00, 0x2E, 0x30, 0x20, 0x20, 0x20, 0x00, // 72 - 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, // 73 - 0x10, 0x10, 0x3C, 0x10, 0x10, 0x12, 0x0C, 0x00, // 74 - 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, // 75 - 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, // 76 - 0x00, 0x00, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x00, // 77 - 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, // 78 - 0x00, 0x00, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, // 79 - 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, // 7A - 0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00, // 7B - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // 7C - 0x38, 0x0C, 0x0C, 0x06, 0x0C, 0x0C, 0x38, 0x00, // 7D - 0x2A, 0x15, 0x2A, 0x15, 0x2A, 0x15, 0x2A, 0x15, // 7E - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // 7F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 81 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 82 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 83 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 84 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 85 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 86 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 87 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8A - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8C - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8F - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 90 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 91 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 92 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 93 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 94 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 95 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 97 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 98 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 99 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9A - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9B - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9C - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9D - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9E - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9F - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A0 - 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, 0xF7, 0xFF, // A1 - 0xEB, 0xEB, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A2 - 0xEB, 0xEB, 0xC1, 0xEB, 0xC1, 0xEB, 0xEB, 0xFF, // A3 - 0xF7, 0xE1, 0xD7, 0xE3, 0xF5, 0xC3, 0xF7, 0xFF, // A4 - 0xCF, 0xCD, 0xFB, 0xF7, 0xEF, 0xD9, 0xF9, 0xFF, // A5 - 0xEF, 0xD7, 0xD7, 0xEF, 0xD5, 0xDB, 0xE5, 0xFF, // A6 - 0xF7, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A7 - 0xF7, 0xEF, 0xDF, 0xDF, 0xDF, 0xEF, 0xF7, 0xFF, // A8 - 0xF7, 0xFB, 0xFD, 0xFD, 0xFD, 0xFB, 0xF7, 0xFF, // A9 - 0xF7, 0xD5, 0xE3, 0xF7, 0xE3, 0xD5, 0xF7, 0xFF, // AA - 0xFF, 0xF7, 0xF7, 0xC1, 0xF7, 0xF7, 0xFF, 0xFF, // AB - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xF7, 0xEF, // AC - 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, // AD - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, // AE - 0xFF, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xFF, 0xFF, // AF - 0xE3, 0xDD, 0xD9, 0xD5, 0xCD, 0xDD, 0xE3, 0xFF, // B0 - 0xF7, 0xE7, 0xF7, 0xF7, 0xF7, 0xF7, 0xE3, 0xFF, // B1 - 0xE3, 0xDD, 0xFD, 0xFB, 0xF7, 0xEF, 0xC1, 0xFF, // B2 - 0xC1, 0xFD, 0xFB, 0xF3, 0xFD, 0xDD, 0xE3, 0xFF, // B3 - 0xFB, 0xF3, 0xEB, 0xDB, 0xC1, 0xFB, 0xFB, 0xFF, // B4 - 0xC1, 0xDF, 0xC3, 0xFD, 0xFD, 0xDD, 0xE3, 0xFF, // B5 - 0xF3, 0xEF, 0xDF, 0xC3, 0xDD, 0xDD, 0xE3, 0xFF, // B6 - 0xC1, 0xFD, 0xFB, 0xF7, 0xEF, 0xEF, 0xEF, 0xFF, // B7 - 0xE3, 0xDD, 0xDD, 0xE3, 0xDD, 0xDD, 0xE3, 0xFF, // B8 - 0xE3, 0xDD, 0xDD, 0xE1, 0xFD, 0xFB, 0xE7, 0xFF, // B9 - 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, // BA - 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7, 0xF7, 0xEF, // BB - 0xFB, 0xF7, 0xEF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFF, // BC - 0xFF, 0xFF, 0xC1, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, // BD - 0xEF, 0xF7, 0xFB, 0xFD, 0xFB, 0xF7, 0xEF, 0xFF, // BE - 0xE3, 0xDD, 0xFB, 0xF7, 0xF7, 0xFF, 0xF7, 0xFF, // BF - 0xE3, 0xDD, 0xD5, 0xD1, 0xD3, 0xDF, 0xE1, 0xFF, // C0 - 0xF7, 0xEB, 0xDD, 0xDD, 0xC1, 0xDD, 0xDD, 0xFF, // C1 - 0xC3, 0xDD, 0xDD, 0xC3, 0xDD, 0xDD, 0xC3, 0xFF, // C2 - 0xE3, 0xDD, 0xDF, 0xDF, 0xDF, 0xDD, 0xE3, 0xFF, // C3 - 0xC3, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xC3, 0xFF, // C4 - 0xC1, 0xDF, 0xDF, 0xC3, 0xDF, 0xDF, 0xC1, 0xFF, // C5 - 0xC1, 0xDF, 0xDF, 0xC3, 0xDF, 0xDF, 0xDF, 0xFF, // C6 - 0xE1, 0xDF, 0xDF, 0xDF, 0xD9, 0xDD, 0xE1, 0xFF, // C7 - 0xDD, 0xDD, 0xDD, 0xC1, 0xDD, 0xDD, 0xDD, 0xFF, // C8 - 0xE3, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xE3, 0xFF, // C9 - 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xDD, 0xE3, 0xFF, // CA - 0xDD, 0xDB, 0xD7, 0xCF, 0xD7, 0xDB, 0xDD, 0xFF, // CB - 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xC1, 0xFF, // CC - 0xDD, 0xC9, 0xD5, 0xD5, 0xDD, 0xDD, 0xDD, 0xFF, // CD - 0xDD, 0xDD, 0xCD, 0xD5, 0xD9, 0xDD, 0xDD, 0xFF, // CE - 0xE3, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xE3, 0xFF, // CF - 0xC3, 0xDD, 0xDD, 0xC3, 0xDF, 0xDF, 0xDF, 0xFF, // D0 - 0xE3, 0xDD, 0xDD, 0xDD, 0xD5, 0xDB, 0xE5, 0xFF, // D1 - 0xC3, 0xDD, 0xDD, 0xC3, 0xD7, 0xDB, 0xDD, 0xFF, // D2 - 0xE3, 0xDD, 0xDF, 0xE3, 0xFD, 0xDD, 0xE3, 0xFF, // D3 - 0xC1, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // D4 - 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xE3, 0xFF, // D5 - 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xEB, 0xF7, 0xFF, // D6 - 0xDD, 0xDD, 0xDD, 0xD5, 0xD5, 0xC9, 0xDD, 0xFF, // D7 - 0xDD, 0xDD, 0xEB, 0xF7, 0xEB, 0xDD, 0xDD, 0xFF, // D8 - 0xDD, 0xDD, 0xEB, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // D9 - 0xC1, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xC1, 0xFF, // DA - 0xE1, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xE1, 0xFF, // DB - 0xFF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFF, 0xFF, // DC - 0xC3, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xC3, 0xFF, // DD - 0xF7, 0xEB, 0xD5, 0xF7, 0xF7, 0xF7, 0xF7, 0xFF, // DE - 0xF1, 0xEE, 0xC3, 0xEF, 0xC3, 0xEE, 0xF1, 0xFF, // DF - 0xF3, 0xED, 0xD2, 0xD6, 0xD6, 0xD2, 0xED, 0xF3, // E0 - 0xFF, 0xFF, 0xE3, 0xFD, 0xE1, 0xDD, 0xE1, 0xFF, // E1 - 0xDF, 0xDF, 0xC3, 0xDD, 0xDD, 0xDD, 0xC3, 0xFF, // E2 - 0xFF, 0xFF, 0xE1, 0xDF, 0xDF, 0xDF, 0xE1, 0xFF, // E3 - 0xFD, 0xFD, 0xE1, 0xDD, 0xDD, 0xDD, 0xE1, 0xFF, // E4 - 0xFF, 0xFF, 0xE3, 0xDD, 0xC1, 0xDF, 0xE1, 0xFF, // E5 - 0xF3, 0xED, 0xEF, 0xC3, 0xEF, 0xEF, 0xEF, 0xFF, // E6 - 0xFF, 0xFF, 0xE3, 0xDD, 0xDD, 0xE1, 0xFD, 0xE3, // E7 - 0xDF, 0xDF, 0xC3, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, // E8 - 0xF7, 0xFF, 0xE7, 0xF7, 0xF7, 0xF7, 0xE3, 0xFF, // E9 - 0xFB, 0xFF, 0xF3, 0xFB, 0xFB, 0xFB, 0xDB, 0xE7, // EA - 0xDF, 0xDF, 0xDD, 0xDB, 0xC7, 0xDB, 0xDD, 0xFF, // EB - 0xE7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xE3, 0xFF, // EC - 0xFF, 0xFF, 0xC9, 0xD5, 0xD5, 0xD5, 0xDD, 0xFF, // ED - 0xFF, 0xFF, 0xC3, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, // EE - 0xFF, 0xFF, 0xE3, 0xDD, 0xDD, 0xDD, 0xE3, 0xFF, // EF - 0xFF, 0xFF, 0xC3, 0xDD, 0xDD, 0xC3, 0xDF, 0xDF, // F0 - 0xFF, 0xFF, 0xE1, 0xDD, 0xDD, 0xE1, 0xFD, 0xFD, // F1 - 0xFF, 0xFF, 0xD1, 0xCF, 0xDF, 0xDF, 0xDF, 0xFF, // F2 - 0xFF, 0xFF, 0xE1, 0xDF, 0xE3, 0xFD, 0xC3, 0xFF, // F3 - 0xEF, 0xEF, 0xC3, 0xEF, 0xEF, 0xED, 0xF3, 0xFF, // F4 - 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xD9, 0xE5, 0xFF, // F5 - 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xEB, 0xF7, 0xFF, // F6 - 0xFF, 0xFF, 0xDD, 0xDD, 0xD5, 0xD5, 0xC9, 0xFF, // F7 - 0xFF, 0xFF, 0xDD, 0xEB, 0xF7, 0xEB, 0xDD, 0xFF, // F8 - 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xE1, 0xFD, 0xE3, // F9 - 0xFF, 0xFF, 0xC1, 0xFB, 0xF7, 0xEF, 0xC1, 0xFF, // FA - 0xF1, 0xE7, 0xE7, 0xCF, 0xE7, 0xE7, 0xF1, 0xFF, // FB - 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, // FC - 0xC7, 0xF3, 0xF3, 0xF9, 0xF3, 0xF3, 0xC7, 0xFF, // FD - 0xD5, 0xEA, 0xD5, 0xEA, 0xD5, 0xEA, 0xD5, 0xEA, // FE - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // FF -}; - -/* - Embedded source code compiled with: - - sokol-shdc -i debugtext.glsl -o debugtext.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b - - (not that for Metal and D3D11 byte code, sokol-shdc must be run - on macOS and Windows) - - @vs vs - in vec2 position; - in vec2 texcoord0; - in vec4 color0; - out vec2 uv; - out vec4 color; - void main() { - gl_Position = vec4(position * vec2(2.0, -2.0) + vec2(-1.0, +1.0), 0.0, 1.0); - uv = texcoord0; - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - in vec2 uv; - in vec4 color; - out vec4 frag_color; - void main() { - frag_color = texture(sampler2D(tex, smp), uv).xxxx * color; - } - @end - - @program debugtext vs fs -*/ -#if defined(SOKOL_GLCORE) -static const uint8_t _sdtx_vs_source_glsl410[343] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x6c,0x61, - 0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, - 0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65, - 0x63,0x32,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f, - 0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76, - 0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6c, - 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, - 0x20,0x31,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, - 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, - 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x66, - 0x6d,0x61,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x76,0x65,0x63, - 0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x76,0x65, - 0x63,0x32,0x28,0x2d,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x29,0x2c,0x20, - 0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75, - 0x76,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20, - 0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sdtx_fs_source_glsl410[224] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, - 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, - 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67, - 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65, - 0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x29,0x2e,0x78,0x78, - 0x78,0x78,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, - -}; -#elif defined(SOKOL_GLES3) -static const uint8_t _sdtx_vs_source_glsl300es[301] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74, - 0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79, - 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32, - 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b, - 0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x2a,0x20,0x76,0x65,0x63,0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e, - 0x30,0x29,0x20,0x2b,0x20,0x76,0x65,0x63,0x32,0x28,0x2d,0x31,0x2e,0x30,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sdtx_fs_source_glsl300es[255] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, - 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x75, - 0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, - 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x29,0x2e,0x78,0x78,0x78, - 0x78,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _sdtx_vs_bytecode_metal_macos[2796] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0xfe,0xa3,0xdd,0x3f,0xa3,0x19,0x66, - 0x48,0xdb,0x53,0x17,0xfa,0x47,0xab,0xcd,0x1c,0x32,0x10,0x34,0x47,0xde,0x1e,0x11, - 0x5c,0xfd,0x36,0x7a,0xb2,0xbe,0x26,0x50,0xa3,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xcc,0x09,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0x70,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x00,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x18,0xc2,0xff,0xff,0xff,0xff,0x0f,0x80,0x04,0x50,0x00, - 0x49,0x18,0x00,0x00,0x02,0x00,0x00,0x00,0x13,0x82,0x60,0x42,0x20,0x00,0x00,0x00, - 0x89,0x20,0x00,0x00,0x11,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04, - 0x13,0x22,0xa4,0x84,0x04,0x13,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c, - 0x0b,0x84,0x84,0x4c,0x10,0x34,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76, - 0x08,0x91,0x42,0x4c,0x84,0x10,0x15,0x22,0x22,0x82,0x6c,0x20,0x60,0x8e,0x00,0x0c, - 0x52,0x20,0x87,0x11,0x88,0x64,0x04,0x00,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48, - 0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83, - 0x76,0x08,0x87,0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38, - 0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0, - 0x07,0x78,0xd0,0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e, - 0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73, - 0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40, - 0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10, - 0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07, - 0x76,0x40,0x07,0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a, - 0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20, - 0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07, - 0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72, - 0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0, - 0x06,0xf6,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07, - 0x71,0x20,0x07,0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70, - 0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0, - 0x07,0x71,0x60,0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x29,0x00,0x00,0x08,0x00,0x00, - 0x00,0x00,0x00,0x18,0xc2,0x1c,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64,0x81, - 0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90, - 0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0xca,0x12,0x18,0x01,0x28,0x82,0x42,0x28,0x08, - 0xd2,0xb1,0x84,0x26,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xb1,0x00,0x00,0x00, - 0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7, - 0x21,0x46,0x42,0x20,0x80,0x72,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3, - 0x2b,0x1b,0x62,0x24,0x02,0x22,0x24,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4, - 0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac, - 0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0x80,0x10, - 0x43,0x8c,0x44,0x48,0x8c,0x64,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x41,0x8e, - 0x44,0x48,0x84,0x64,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56, - 0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56, - 0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65, - 0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c, - 0x65,0x43,0x04,0x64,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1, - 0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95, - 0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x90,0x86,0x51, - 0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d, - 0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69, - 0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34, - 0xcc,0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9, - 0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20,0x0f,0x02,0x21,0x11,0x22,0x21,0x13, - 0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6, - 0xf6,0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08,0x83,0x3c,0x88,0x85, - 0x44,0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e, - 0xed,0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10, - 0x05,0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86,0x18,0x48,0x85,0x64,0x08,0x47,0x28, - 0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e, - 0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b, - 0x59,0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32,0x32,0x94,0xaf,0xaf, - 0xb0,0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf, - 0xaf,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43,0xa8,0x64,0x40,0x3c, - 0xe4,0x4b,0x86,0x44,0x40,0xc0,0x00,0x89,0x10,0x09,0x99,0x90,0x30,0x60,0x42,0x57, - 0x86,0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84,0x4a,0x04,0xc4,0x43,0xbe,0x44,0x48, - 0x04,0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72, - 0x30,0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88,0x44,0x40,0xc0,0x00,0x89,0x90,0x0b, - 0x99,0x90,0x32,0x18,0x62,0x20,0x62,0x80,0x90,0x01,0x62,0x06,0x43,0x8c,0x02,0x40, - 0x3a,0xe4,0x0c,0x46,0x44,0xec,0xc0,0x0e,0xf6,0xd0,0x0e,0x6e,0xd0,0x0e,0xef,0x40, - 0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0,0x0e,0xe1,0x70,0x0e,0xf3,0x30,0x45, - 0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b,0xa4,0x03,0x39,0x94,0x83, - 0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39, - 0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94,0xc0,0x18,0x41,0x85,0x43,0x3a,0xc8, - 0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4,0x43,0x38,0x9c,0x43,0x39,0xfc,0x82, - 0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83,0x3b,0x4c,0x09,0x90,0x11,0x53,0x38, - 0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b,0xc0,0x43,0x3a,0xb0,0x43,0x39,0xfc, - 0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x3c,0x4c,0x19,0x14,0xc6,0x19, - 0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8,0x03,0x3d,0x94,0x03,0x3e, - 0x4c,0x09,0xd0,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c, - 0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07, - 0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e, - 0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43, - 0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c, - 0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76, - 0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e, - 0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8, - 0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4, - 0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68, - 0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07, - 0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71, - 0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5, - 0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4, - 0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90, - 0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43, - 0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b, - 0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78, - 0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2, - 0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20, - 0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0, - 0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83, - 0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07, - 0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61, - 0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d, - 0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39, - 0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79, - 0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3, - 0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4, - 0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8, - 0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83, - 0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x05,0x00,0x00,0x00, - 0x06,0x50,0x30,0x00,0xd2,0xd0,0x16,0xd0,0x00,0x48,0xe4,0x17,0x0c,0xe0,0x57,0x76, - 0x71,0xdb,0x00,0x00,0x61,0x20,0x00,0x00,0x1b,0x00,0x00,0x00,0x13,0x04,0x41,0x2c, - 0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0xb4,0x63,0x11,0x40,0x60,0x1c,0x73,0x10, - 0x83,0xd0,0x34,0x94,0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82,0x20,0x18,0x80,0x20, - 0x08,0x82,0xe0,0x30,0x96,0x00,0x82,0x20,0x88,0xff,0x02,0x08,0x82,0x20,0xfe,0xcd, - 0x00,0x90,0xcc,0x41,0x54,0x15,0x35,0xd1,0xcc,0x00,0x10,0x8c,0x11,0x80,0x20,0x08, - 0xe2,0xdf,0x08,0xc0,0x0c,0x00,0x00,0x00,0x23,0x06,0x86,0x10,0x54,0x0e,0x72,0x0c, - 0x32,0x04,0xc7,0x32,0xc8,0x10,0x1c,0xcd,0x6c,0xc3,0x01,0x01,0xb3,0x0d,0x01,0x14, - 0xcc,0x36,0x04,0x83,0x90,0x01,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sdtx_fs_bytecode_metal_macos[2825] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x09,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x30,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xf6,0x61,0xa5,0x24,0x2e,0x8e,0x25, - 0x56,0xa9,0xb9,0xe4,0x35,0x58,0x0f,0xd8,0xb4,0x32,0x8b,0xbc,0x73,0xb0,0x70,0xbe, - 0x5d,0x66,0xf0,0xf4,0x12,0x93,0x26,0xe5,0xdd,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x1c,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x84,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1e,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x4c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x30,0x02,0xb1,0x8c,0x00,0x00,0x00,0x00,0x00,0x13,0xb2,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x76,0x08,0x87,0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83, - 0x38,0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78, - 0xa0,0x07,0x78,0xd0,0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90, - 0x0e,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e, - 0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76, - 0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20, - 0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30, - 0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07, - 0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71, - 0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20, - 0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f, - 0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76, - 0xd0,0x06,0xf6,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50, - 0x07,0x71,0x20,0x07,0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78, - 0xa0,0x07,0x71,0x60,0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00, - 0x00,0x00,0x00,0x00,0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64, - 0x81,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50, - 0x10,0x65,0x40,0x70,0x2c,0xa1,0x09,0x00,0x00,0x79,0x18,0x00,0x00,0xb9,0x00,0x00, - 0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37, - 0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b, - 0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c, - 0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26, - 0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac, - 0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0, - 0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79, - 0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6, - 0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6, - 0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62, - 0x6c,0x65,0x43,0x84,0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5, - 0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99, - 0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86, - 0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59, - 0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f, - 0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c, - 0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd, - 0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08, - 0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b, - 0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c, - 0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72, - 0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34,0xcc,0xd8,0xde, - 0xc2,0xe8,0x64,0x28,0xd4,0xd9,0x0d,0x91,0x96,0xe1,0xb1,0x9e,0xeb,0xc1,0x9e,0xec, - 0x81,0x1e,0xed,0x91,0x9e,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x5b, - 0x4c,0x0a,0x8b,0xb1,0x37,0xb6,0x37,0xb9,0x21,0xd2,0x22,0x3c,0xd6,0xd3,0x3d,0xd8, - 0x93,0x3d,0xd0,0x13,0x3d,0xd2,0xe3,0x71,0x09,0x4b,0x93,0x73,0xa1,0x2b,0xc3,0xa3, - 0xab,0x93,0x2b,0xa3,0x14,0x96,0x26,0xe7,0xc2,0xf6,0x36,0x16,0x46,0x97,0xf6,0xe6, - 0xf6,0x95,0xe6,0x46,0x56,0x86,0x47,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e, - 0xad,0x8c,0x18,0x5d,0x19,0x1e,0x5d,0x9d,0x5c,0x99,0x0c,0x19,0x8f,0x19,0xdb,0x5b, - 0x18,0x1d,0x0b,0xc8,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x0f,0x07,0xba,0x32,0xbc,0x21, - 0xd4,0x42,0x3c,0x60,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x23,0x06,0x0f,0xf4,0x8c,0xc1, - 0x23,0x3d,0x64,0xc0,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x4c,0x8e, - 0xc7,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x87,0xb9,0x36,0xb8,0x21,0xd2,0x72,0x3c, - 0x66,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x03,0x3d,0x67,0xf0,0x48,0x0f,0x1a,0x0c,0x41, - 0x1e,0xee,0xf9,0x9e,0x32,0x78,0xd2,0x60,0x88,0x91,0x00,0x4f,0xf5,0xa8,0xc1,0x88, - 0x88,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xda,0xe1,0x1d,0xc8,0xa1,0x1e,0xd8,0xa1, - 0x1c,0xdc,0xc0,0x1c,0xd8,0x21,0x1c,0xce,0x61,0x1e,0xa6,0x08,0xc1,0x30,0x42,0x61, - 0x07,0x76,0xb0,0x87,0x76,0x70,0x83,0x74,0x20,0x87,0x72,0x70,0x07,0x7a,0x98,0x12, - 0x14,0x23,0x96,0x70,0x48,0x07,0x79,0x70,0x03,0x7b,0x28,0x07,0x79,0x98,0x87,0x74, - 0x78,0x07,0x77,0x98,0x12,0x18,0x23,0xa8,0x70,0x48,0x07,0x79,0x70,0x03,0x76,0x08, - 0x07,0x77,0x38,0x87,0x7a,0x08,0x87,0x73,0x28,0x87,0x5f,0xb0,0x87,0x72,0x90,0x87, - 0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x01,0x32,0x62,0x0a,0x87,0x74,0x90,0x07,0x37, - 0x18,0x87,0x77,0x68,0x07,0x78,0x48,0x07,0x76,0x28,0x87,0x5f,0x78,0x07,0x78,0xa0, - 0x87,0x74,0x78,0x07,0x77,0x98,0x87,0x29,0x83,0xc2,0x38,0x23,0x98,0x70,0x48,0x07, - 0x79,0x70,0x03,0x73,0x90,0x87,0x70,0x38,0x87,0x76,0x28,0x07,0x77,0xa0,0x87,0x29, - 0xc1,0x1a,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80, - 0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80, - 0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80, - 0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88, - 0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78, - 0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03, - 0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f, - 0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c, - 0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39, - 0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60, - 0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87, - 0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e, - 0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c, - 0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6, - 0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94, - 0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03, - 0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07, - 0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f, - 0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33, - 0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc, - 0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c, - 0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78, - 0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca, - 0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21, - 0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43, - 0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87, - 0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c, - 0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e, - 0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c, - 0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c, - 0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00, - 0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45, - 0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00, - 0x00,0x61,0x20,0x00,0x00,0x0f,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00, - 0x00,0x06,0x00,0x00,0x00,0x14,0x47,0x00,0x88,0x8d,0x00,0x90,0x1a,0x01,0xa8,0x01, - 0x12,0x33,0x00,0x14,0x66,0x00,0x08,0x8c,0x00,0x00,0x00,0x00,0x00,0x23,0x06,0x8a, - 0x10,0x4c,0x09,0xb2,0x10,0x46,0x11,0x0c,0x32,0x04,0x03,0x62,0x01,0x23,0x9f,0xd9, - 0x06,0x23,0x00,0x32,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sdtx_vs_bytecode_metal_ios[2796] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0xba,0x9f,0x15,0xc2,0x1c,0x90,0x81, - 0x14,0x52,0x1d,0xff,0x02,0xbe,0x84,0x58,0x4b,0x16,0xdb,0x77,0xe8,0xfc,0xb2,0x67, - 0xb1,0x23,0xf1,0x84,0xb0,0x8d,0xed,0xb3,0x81,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xc4,0x09,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0x6e,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x00,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x18,0xc2,0xff,0xff,0xff,0xff,0x0f,0x80,0x04,0x50,0x00, - 0x49,0x18,0x00,0x00,0x02,0x00,0x00,0x00,0x13,0x82,0x60,0x42,0x20,0x00,0x00,0x00, - 0x89,0x20,0x00,0x00,0x11,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04, - 0x13,0x22,0xa4,0x84,0x04,0x13,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c, - 0x0b,0x84,0x84,0x4c,0x10,0x34,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76, - 0x08,0x91,0x42,0x4c,0x84,0x10,0x15,0x22,0x22,0x82,0x6c,0x20,0x60,0x8e,0x00,0x0c, - 0x52,0x20,0x87,0x11,0x88,0x64,0x04,0x00,0x00,0x00,0x00,0x00,0x13,0xa8,0x70,0x48, - 0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83, - 0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e, - 0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0, - 0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0, - 0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6, - 0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07, - 0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6, - 0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80, - 0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07, - 0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75, - 0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0, - 0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07, - 0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70, - 0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20, - 0x07,0x43,0x98,0x02,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0xcc,0x01,0x04, - 0x80,0x00,0x00,0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0xca, - 0x12,0x18,0x01,0x28,0x82,0x42,0x28,0x08,0xd2,0xb1,0x04,0x48,0x00,0x00,0x00,0x00, - 0x79,0x18,0x00,0x00,0xb1,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25, - 0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0x46,0x42,0x20,0x80,0x72,0x50,0xb9, - 0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x24,0x02,0x22,0x24,0x05, - 0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c, - 0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04, - 0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6, - 0xe6,0xc6,0x45,0x26,0x65,0x88,0x80,0x10,0x43,0x8c,0x44,0x48,0x8c,0x64,0x60,0xd1, - 0x54,0x46,0x17,0xc6,0x36,0x04,0x41,0x8e,0x44,0x48,0x84,0x64,0xe0,0x16,0x96,0x26, - 0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36, - 0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72, - 0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61, - 0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x64,0x21,0x19,0x84,0xa5, - 0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89, - 0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89, - 0xb1,0x95,0x0d,0x11,0x90,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19, - 0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7, - 0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70, - 0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5, - 0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20, - 0x0f,0x02,0x21,0x11,0x22,0x21,0x13,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b, - 0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6,0xf6,0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed, - 0x4d,0x6e,0x08,0x83,0x3c,0x88,0x85,0x44,0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d, - 0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb, - 0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10,0x05,0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86, - 0x18,0x48,0x85,0x64,0x08,0x47,0x28,0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c, - 0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18, - 0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9, - 0x30,0xba,0x32,0x32,0x94,0xaf,0xaf,0xb0,0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32, - 0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf,0xaf,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x43,0xa8,0x64,0x40,0x3c,0xe4,0x4b,0x86,0x44,0x40,0xc0,0x00,0x89,0x10, - 0x09,0x99,0x90,0x30,0x60,0x42,0x57,0x86,0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84, - 0x4a,0x04,0xc4,0x43,0xbe,0x44,0x48,0x04,0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19, - 0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88, - 0x44,0x40,0xc0,0x00,0x89,0x90,0x0b,0x99,0x90,0x32,0x18,0x62,0x20,0x62,0x80,0x90, - 0x01,0x62,0x06,0x43,0x8c,0x02,0x40,0x3a,0xe4,0x0c,0x46,0x44,0xec,0xc0,0x0e,0xf6, - 0xd0,0x0e,0x6e,0xd0,0x0e,0xef,0x40,0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0, - 0x0e,0xe1,0x70,0x0e,0xf3,0x30,0x45,0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4, - 0x83,0x1b,0xa4,0x03,0x39,0x94,0x83,0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43, - 0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94, - 0xc0,0x18,0x41,0x85,0x43,0x3a,0xc8,0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4, - 0x43,0x38,0x9c,0x43,0x39,0xfc,0x82,0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83, - 0x3b,0x4c,0x09,0x90,0x11,0x53,0x38,0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b, - 0xc0,0x43,0x3a,0xb0,0x43,0x39,0xfc,0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8, - 0xc3,0x3c,0x4c,0x19,0x14,0xc6,0x19,0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43, - 0x39,0xc8,0x03,0x3d,0x94,0x03,0x3e,0x4c,0x09,0xd0,0x00,0x00,0x79,0x18,0x00,0x00, - 0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88, - 0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6, - 0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce, - 0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8, - 0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48, - 0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11, - 0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e, - 0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89, - 0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b, - 0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37, - 0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78, - 0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81, - 0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1, - 0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c, - 0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39, - 0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc, - 0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58, - 0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87, - 0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f, - 0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e, - 0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66, - 0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0, - 0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e, - 0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc, - 0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3, - 0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07, - 0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e, - 0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e, - 0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d, - 0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00, - 0x71,0x20,0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x16,0xd0, - 0x00,0x48,0xe4,0x17,0x0c,0xe0,0x57,0x76,0x71,0xdb,0x00,0x00,0x61,0x20,0x00,0x00, - 0x1b,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00, - 0xb4,0x63,0x11,0x40,0x60,0x1c,0x73,0x10,0x83,0xd0,0x34,0x94,0x33,0x00,0x14,0x63, - 0x09,0x20,0x08,0x82,0x20,0x18,0x80,0x20,0x08,0x82,0xe0,0x30,0x96,0x00,0x82,0x20, - 0x88,0xff,0x02,0x08,0x82,0x20,0xfe,0xcd,0x00,0x90,0xcc,0x41,0x54,0x15,0x35,0xd1, - 0xcc,0x00,0x10,0x8c,0x11,0x80,0x20,0x08,0xe2,0xdf,0x08,0xc0,0x0c,0x00,0x00,0x00, - 0x23,0x06,0x86,0x10,0x54,0x0e,0x72,0x0c,0x32,0x04,0xc7,0x32,0xc8,0x10,0x1c,0xcd, - 0x6c,0xc3,0x01,0x01,0xb3,0x0d,0x01,0x14,0xcc,0x36,0x04,0x83,0x90,0x01,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sdtx_fs_bytecode_metal_ios[2825] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x09,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x30,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0x5c,0x3b,0x31,0x10,0xb3,0x9b,0xe2, - 0x6d,0x48,0xbf,0xdd,0x8e,0xac,0x5d,0xcc,0x7d,0x7b,0xba,0xe9,0xfb,0xe5,0xd0,0xdd, - 0xf7,0xec,0x82,0x0c,0xb9,0x6a,0xd2,0x30,0x4d,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x14,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x82,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1e,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x4c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x30,0x02,0xb1,0x8c,0x00,0x00,0x00,0x00,0x00,0x13,0xa8,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51, - 0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78, - 0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0, - 0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90, - 0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06, - 0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72, - 0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10, - 0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73, - 0x20,0x07,0x43,0x98,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03, - 0x04,0x80,0x00,0x00,0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00, - 0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43, - 0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0x01,0x12,0x00, - 0x00,0x79,0x18,0x00,0x00,0xb9,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2, - 0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50, - 0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c, - 0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae, - 0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06, - 0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60, - 0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96, - 0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7, - 0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69, - 0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d, - 0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x21,0x19,0x84, - 0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95, - 0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85, - 0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59, - 0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9, - 0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61, - 0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8, - 0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e, - 0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08,0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e, - 0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99, - 0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37, - 0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74, - 0x69,0x76,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28,0xd4,0xd9,0x0d,0x91,0x96, - 0xe1,0xb1,0x9e,0xeb,0xc1,0x9e,0xec,0x81,0x1e,0xed,0x91,0x9e,0x8d,0x4b,0xdd,0x5c, - 0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1,0x37,0xb6,0x37,0xb9,0x21, - 0xd2,0x22,0x3c,0xd6,0xd3,0x3d,0xd8,0x93,0x3d,0xd0,0x13,0x3d,0xd2,0xe3,0x71,0x09, - 0x4b,0x93,0x73,0xa1,0x2b,0xc3,0xa3,0xab,0x93,0x2b,0xa3,0x14,0x96,0x26,0xe7,0xc2, - 0xf6,0x36,0x16,0x46,0x97,0xf6,0xe6,0xf6,0x95,0xe6,0x46,0x56,0x86,0x47,0x25,0x2c, - 0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x8c,0x18,0x5d,0x19,0x1e,0x5d,0x9d,0x5c, - 0x99,0x0c,0x19,0x8f,0x19,0xdb,0x5b,0x18,0x1d,0x0b,0xc8,0x5c,0x58,0x1b,0x1c,0x5b, - 0x99,0x0f,0x07,0xba,0x32,0xbc,0x21,0xd4,0x42,0x3c,0x60,0xf0,0x84,0xc1,0x32,0x2c, - 0xc2,0x23,0x06,0x0f,0xf4,0x8c,0xc1,0x23,0x3d,0x64,0xc0,0x25,0x2c,0x4d,0xce,0x65, - 0x2e,0xac,0x0d,0x8e,0xad,0x4c,0x8e,0xc7,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x87, - 0xb9,0x36,0xb8,0x21,0xd2,0x72,0x3c,0x66,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x03,0x3d, - 0x67,0xf0,0x48,0x0f,0x1a,0x0c,0x41,0x1e,0xee,0xf9,0x9e,0x32,0x78,0xd2,0x60,0x88, - 0x91,0x00,0x4f,0xf5,0xa8,0xc1,0x88,0x88,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xda, - 0xe1,0x1d,0xc8,0xa1,0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c,0xd8,0x21,0x1c,0xce,0x61, - 0x1e,0xa6,0x08,0xc1,0x30,0x42,0x61,0x07,0x76,0xb0,0x87,0x76,0x70,0x83,0x74,0x20, - 0x87,0x72,0x70,0x07,0x7a,0x98,0x12,0x14,0x23,0x96,0x70,0x48,0x07,0x79,0x70,0x03, - 0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78,0x07,0x77,0x98,0x12,0x18,0x23,0xa8,0x70, - 0x48,0x07,0x79,0x70,0x03,0x76,0x08,0x07,0x77,0x38,0x87,0x7a,0x08,0x87,0x73,0x28, - 0x87,0x5f,0xb0,0x87,0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x01,0x32, - 0x62,0x0a,0x87,0x74,0x90,0x07,0x37,0x18,0x87,0x77,0x68,0x07,0x78,0x48,0x07,0x76, - 0x28,0x87,0x5f,0x78,0x07,0x78,0xa0,0x87,0x74,0x78,0x07,0x77,0x98,0x87,0x29,0x83, - 0xc2,0x38,0x23,0x98,0x70,0x48,0x07,0x79,0x70,0x03,0x73,0x90,0x87,0x70,0x38,0x87, - 0x76,0x28,0x07,0x77,0xa0,0x87,0x29,0xc1,0x1a,0x00,0x00,0x00,0x00,0x79,0x18,0x00, - 0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d, - 0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c, - 0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d, - 0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d, - 0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79, - 0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc, - 0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50, - 0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30, - 0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03, - 0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07, - 0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76, - 0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98, - 0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8, - 0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21, - 0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43, - 0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f, - 0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70, - 0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0, - 0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40, - 0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41, - 0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e, - 0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07, - 0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f, - 0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d, - 0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38, - 0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88, - 0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08, - 0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50, - 0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01, - 0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03, - 0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c, - 0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00, - 0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d, - 0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x0f,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x14,0x47,0x00, - 0x88,0x8d,0x00,0x90,0x1a,0x01,0xa8,0x01,0x12,0x33,0x00,0x14,0x66,0x00,0x08,0x8c, - 0x00,0x00,0x00,0x00,0x00,0x23,0x06,0x8a,0x10,0x4c,0x09,0xb2,0x10,0x46,0x11,0x0c, - 0x32,0x04,0x03,0x62,0x01,0x23,0x9f,0xd9,0x06,0x23,0x00,0x32,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sdtx_vs_source_metal_sim[577] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28, - 0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65, - 0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x20,0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b, - 0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e, - 0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74,0x74, - 0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64, - 0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74, - 0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74, - 0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20, - 0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74, - 0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67, - 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x34,0x28,0x66,0x6d,0x61,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x32,0x2e,0x30,0x2c, - 0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x2d, - 0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x29,0x2c,0x20,0x30,0x2e,0x30,0x2c, - 0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75, - 0x76,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30, - 0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x20, - 0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a, - 0x00, -}; -static const uint8_t _sdtx_fs_source_metal_sim[441] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65, - 0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65, - 0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d, - 0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b, - 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, - 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, - 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e, - 0x75,0x76,0x29,0x2e,0x78,0x78,0x78,0x78,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f, - 0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20, - 0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _sdtx_vs_bytecode_hlsl4[692] = { - 0x44,0x58,0x42,0x43,0x07,0x05,0xa0,0xb3,0x53,0xc1,0x0a,0x0d,0x1e,0xf4,0xe4,0xa6, - 0x91,0xaf,0x4c,0xca,0x01,0x00,0x00,0x00,0xb4,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xe4,0x00,0x00,0x00,0x54,0x01,0x00,0x00, - 0x38,0x02,0x00,0x00,0x52,0x44,0x45,0x46,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0x1c,0x00,0x00,0x00,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66, - 0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65, - 0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00, - 0x49,0x53,0x47,0x4e,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x03,0x00,0x00, - 0x50,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0c,0x00,0x00,0x50,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x0f,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43, - 0x4f,0x4f,0x52,0x44,0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x00,0xab,0xab,0xab,0x53,0x48,0x44,0x52,0xdc,0x00,0x00,0x00,0x40,0x00,0x01,0x00, - 0x37,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, - 0xf2,0x10,0x10,0x00,0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0x32,0x20,0x10,0x00, - 0x00,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00, - 0x67,0x00,0x00,0x04,0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x36,0x00,0x00,0x05,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00, - 0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00,0x32,0x00,0x00,0x0f,0x32,0x20,0x10,0x00, - 0x02,0x00,0x00,0x00,0x46,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x02,0x40,0x00,0x00, - 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x02,0x40,0x00,0x00,0x00,0x00,0x80,0xbf,0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x08,0xc2,0x20,0x10,0x00,0x02,0x00,0x00,0x00, - 0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x80,0x3f,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, -}; -static const uint8_t _sdtx_fs_bytecode_hlsl4[608] = { - 0x44,0x58,0x42,0x43,0xb7,0xcd,0xbd,0xb1,0x6f,0x85,0x5d,0x59,0x07,0x7e,0xa3,0x6e, - 0xe2,0x23,0x68,0xa0,0x01,0x00,0x00,0x00,0x60,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x48,0x01,0x00,0x00, - 0xe4,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0x64,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c, - 0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00, - 0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54, - 0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0x94,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00, - 0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00, - 0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x06,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00, - 0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -#elif defined(SOKOL_WGPU) -static const uint8_t _sdtx_vs_source_wgsl[922] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70, - 0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74, - 0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a, - 0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20, - 0x7b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x31,0x39,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f, - 0x31,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x37,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x28,0x28,0x78,0x5f,0x31,0x39,0x20,0x2a, - 0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x32,0x2e,0x30,0x66,0x2c,0x20,0x2d,0x32,0x2e, - 0x30,0x66,0x29,0x29,0x20,0x2b,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x2d,0x31,0x2e, - 0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x29,0x3b,0x0a,0x20,0x20,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34, - 0x66,0x28,0x78,0x5f,0x32,0x37,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32,0x37,0x2e,0x79, - 0x2c,0x20,0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x20, - 0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x32, - 0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20, - 0x20,0x75,0x76,0x20,0x3d,0x20,0x78,0x5f,0x33,0x37,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x34,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3d,0x20,0x78,0x5f,0x34,0x31,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72, - 0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c,0x74, - 0x69,0x6e,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20,0x67, - 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x30,0x29,0x0a,0x20,0x20,0x75,0x76,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x32, - 0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31, - 0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x28,0x30,0x29,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78,0x63, - 0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x32,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x32, - 0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f, - 0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72, - 0x64,0x30,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74, - 0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sdtx_fs_source_wgsl[663] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x34,0x38, - 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, - 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x36,0x34,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x78,0x5f,0x32,0x33,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x32,0x38,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x28,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x32, - 0x34,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32,0x34,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32, - 0x34,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32,0x34,0x2e,0x78,0x29,0x20,0x2a,0x20,0x78, - 0x5f,0x32,0x38,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f, - 0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x28,0x30,0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40, - 0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b, - 0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31, - 0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69, - 0x6e,0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _sdtx_vs_src_dummy = ""; -static const char* _sdtx_fs_src_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██████ ██ ██ ██ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██████ ██████ ██ ███████ -// -// >>structs -typedef struct { - uint32_t id; - sg_resource_state state; -} _sdtx_slot_t; - -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _sdtx_pool_t; - -typedef struct { - float x, y; -} _sdtx_float2_t; - -typedef struct { - float x, y; - uint16_t u, v; - uint32_t color; -} _sdtx_vertex_t; - -typedef struct { - int layer_id; - int first_vertex; - int num_vertices; -} _sdtx_command_t; - -typedef struct { - _sdtx_slot_t slot; - sdtx_context_desc_t desc; - uint32_t frame_id; - uint32_t update_frame_id; - struct { - int cap; - int next; - _sdtx_vertex_t* ptr; - } vertices; - struct { - int cap; - int next; - _sdtx_command_t* ptr; - } commands; - sg_buffer vbuf; - sg_pipeline pip; - int cur_font; - int cur_layer_id; - _sdtx_float2_t canvas_size; - _sdtx_float2_t glyph_size; - _sdtx_float2_t origin; - _sdtx_float2_t pos; - float tab_width; - uint32_t color; -} _sdtx_context_t; - -typedef struct { - _sdtx_pool_t pool; - _sdtx_context_t* contexts; -} _sdtx_context_pool_t; - -typedef struct { - uint32_t init_cookie; - sdtx_desc_t desc; - sg_image font_img; - sg_sampler font_smp; - sg_shader shader; - uint32_t fmt_buf_size; - char* fmt_buf; - sdtx_context def_ctx_id; - sdtx_context cur_ctx_id; - _sdtx_context_t* cur_ctx; // may be 0! - _sdtx_context_pool_t context_pool; - uint8_t font_pixels[SDTX_MAX_FONTS * 256 * 8 * 8]; -} _sdtx_t; -static _sdtx_t _sdtx; - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SDTX_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _sdtx_log_messages[] = { - _SDTX_LOG_ITEMS -}; -#undef _SDTX_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SDTX_PANIC(code) _sdtx_log(SDTX_LOGITEM_ ##code, 0, __LINE__) -#define _SDTX_ERROR(code) _sdtx_log(SDTX_LOGITEM_ ##code, 1, __LINE__) -#define _SDTX_WARN(code) _sdtx_log(SDTX_LOGITEM_ ##code, 2, __LINE__) -#define _SDTX_INFO(code) _sdtx_log(SDTX_LOGITEM_ ##code, 3, __LINE__) - -static void _sdtx_log(sdtx_log_item_t log_item, uint32_t log_level, uint32_t line_nr) { - if (_sdtx.desc.logger.func) { - #if defined(SOKOL_DEBUG) - const char* filename = __FILE__; - const char* message = _sdtx_log_messages[log_item]; - #else - const char* filename = 0; - const char* message = 0; - #endif - _sdtx.desc.logger.func("sdtx", log_level, log_item, message, line_nr, filename, _sdtx.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -static void _sdtx_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -static void* _sdtx_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_sdtx.desc.allocator.alloc_fn) { - ptr = _sdtx.desc.allocator.alloc_fn(size, _sdtx.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SDTX_PANIC(MALLOC_FAILED); - } - return ptr; -} - -static void* _sdtx_malloc_clear(size_t size) { - void* ptr = _sdtx_malloc(size); - _sdtx_clear(ptr, size); - return ptr; -} - -static void _sdtx_free(void* ptr) { - if (_sdtx.desc.allocator.free_fn) { - _sdtx.desc.allocator.free_fn(ptr, _sdtx.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ██████ ██████ ███ ██ ████████ ███████ ██ ██ ████████ ██████ ██████ ██████ ██ -// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ █████ ███ ██ ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██ ████ ██ ███████ ██ ██ ██ ██ ██████ ██████ ███████ -// -// >>context pool -static void _sdtx_init_pool(_sdtx_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - // slot 0 is reserved for the 'invalid id', so bump the pool size by 1 - pool->size = num + 1; - pool->queue_top = 0; - // generation counters indexable by pool slot index, slot 0 is reserved - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*) _sdtx_malloc_clear(gen_ctrs_size); - // it's not a bug to only reserve 'num' here - pool->free_queue = (int*) _sdtx_malloc_clear(sizeof(int) * (size_t)num); - // never allocate the zero-th pool item since the invalid id is 0 - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -static void _sdtx_discard_pool(_sdtx_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _sdtx_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _sdtx_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -static int _sdtx_pool_alloc_index(_sdtx_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SDTX_INVALID_SLOT_INDEX; - } -} - -static void _sdtx_pool_free_index(_sdtx_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SDTX_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - // debug check against double-free - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -static void _sdtx_setup_context_pool(const sdtx_desc_t* desc) { - SOKOL_ASSERT(desc); - // note: the pool will have an additional item, since slot 0 is reserved - SOKOL_ASSERT((desc->context_pool_size > 0) && (desc->context_pool_size < _SDTX_MAX_POOL_SIZE)); - _sdtx_init_pool(&_sdtx.context_pool.pool, desc->context_pool_size); - size_t pool_byte_size = sizeof(_sdtx_context_t) * (size_t)_sdtx.context_pool.pool.size; - _sdtx.context_pool.contexts = (_sdtx_context_t*) _sdtx_malloc_clear(pool_byte_size); -} - -static void _sdtx_discard_context_pool(void) { - SOKOL_ASSERT(_sdtx.context_pool.contexts); - _sdtx_free(_sdtx.context_pool.contexts); - _sdtx.context_pool.contexts = 0; - _sdtx_discard_pool(&_sdtx.context_pool.pool); -} - -/* allocate the slot at slot_index: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the resource id -*/ -static uint32_t _sdtx_slot_alloc(_sdtx_pool_t* pool, _sdtx_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SDTX_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT((slot->state == SG_RESOURCESTATE_INITIAL) && (slot->id == SG_INVALID_ID)); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SDTX_SLOT_SHIFT)|(slot_index & _SDTX_SLOT_MASK); - slot->state = SG_RESOURCESTATE_ALLOC; - return slot->id; -} - -// extract slot index from id -static int _sdtx_slot_index(uint32_t id) { - int slot_index = (int) (id & _SDTX_SLOT_MASK); - SOKOL_ASSERT(_SDTX_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -// get context pointer without id-check -static _sdtx_context_t* _sdtx_context_at(uint32_t ctx_id) { - SOKOL_ASSERT(SG_INVALID_ID != ctx_id); - int slot_index = _sdtx_slot_index(ctx_id); - SOKOL_ASSERT((slot_index > _SDTX_INVALID_SLOT_INDEX) && (slot_index < _sdtx.context_pool.pool.size)); - return &_sdtx.context_pool.contexts[slot_index]; -} - -// get context pointer with id-check, returns 0 if no match -static _sdtx_context_t* _sdtx_lookup_context(uint32_t ctx_id) { - if (SG_INVALID_ID != ctx_id) { - _sdtx_context_t* ctx = _sdtx_context_at(ctx_id); - if (ctx->slot.id == ctx_id) { - return ctx; - } - } - return 0; -} - -// make context handle from raw uint32_t id -static sdtx_context _sdtx_make_ctx_id(uint32_t ctx_id) { - sdtx_context ctx; - ctx.id = ctx_id; - return ctx; -} - -static sdtx_context _sdtx_alloc_context(void) { - sdtx_context ctx_id; - int slot_index = _sdtx_pool_alloc_index(&_sdtx.context_pool.pool); - if (_SDTX_INVALID_SLOT_INDEX != slot_index) { - ctx_id = _sdtx_make_ctx_id(_sdtx_slot_alloc(&_sdtx.context_pool.pool, &_sdtx.context_pool.contexts[slot_index].slot, slot_index)); - } else { - // pool is exhausted - ctx_id = _sdtx_make_ctx_id(SG_INVALID_ID); - } - return ctx_id; -} - -static sdtx_context_desc_t _sdtx_context_desc_defaults(const sdtx_context_desc_t* desc) { - sdtx_context_desc_t res = *desc; - res.max_commands = _sdtx_def(res.max_commands, _SDTX_DEFAULT_MAX_COMMANDS); - res.char_buf_size = _sdtx_def(res.char_buf_size, _SDTX_DEFAULT_CHAR_BUF_SIZE); - res.canvas_width = _sdtx_def(res.canvas_width, _SDTX_DEFAULT_CANVAS_WIDTH); - res.canvas_height = _sdtx_def(res.canvas_height, _SDTX_DEFAULT_CANVAS_HEIGHT); - res.tab_width = _sdtx_def(res.tab_width, _SDTX_DEFAULT_TAB_WIDTH); - // keep pixel format attrs are passed as is into pipeline creation - SOKOL_ASSERT(res.char_buf_size > 0); - SOKOL_ASSERT(!isnan(res.canvas_width)); - SOKOL_ASSERT(!isnan(res.canvas_height)); - SOKOL_ASSERT(res.canvas_width > 0.0f); - SOKOL_ASSERT(res.canvas_height > 0.0f); - return res; -} - -static void _sdtx_set_layer(_sdtx_context_t* ctx, int layer_id); -static void _sdtx_rewind(_sdtx_context_t* ctx) { - SOKOL_ASSERT(ctx); - ctx->frame_id++; - ctx->vertices.next = 0; - ctx->commands.next = 0; - _sdtx_set_layer(ctx, 0); - ctx->cur_font = 0; - ctx->pos.x = 0.0f; - ctx->pos.y = 0.0f; -} - -static void _sdtx_commit_listener(void* userdata) { - _sdtx_context_t* ctx = _sdtx_lookup_context((uint32_t)(uintptr_t)userdata); - if (ctx) { - _sdtx_rewind(ctx); - } -} - -static sg_commit_listener _sdtx_make_commit_listener(_sdtx_context_t* ctx) { - sg_commit_listener listener = { _sdtx_commit_listener, (void*)(uintptr_t)(ctx->slot.id) }; - return listener; -} - -static void _sdtx_init_context(sdtx_context ctx_id, const sdtx_context_desc_t* in_desc) { - sg_push_debug_group("sokol-debugtext"); - - SOKOL_ASSERT((ctx_id.id != SG_INVALID_ID) && in_desc); - _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - SOKOL_ASSERT(ctx); - ctx->desc = _sdtx_context_desc_defaults(in_desc); - // NOTE: frame_id must be non-zero, so that updates trigger in first frame - ctx->frame_id = 1; - - ctx->vertices.cap = 6 * ctx->desc.char_buf_size; - const size_t vbuf_size = (size_t)ctx->vertices.cap * sizeof(_sdtx_vertex_t); - ctx->vertices.ptr = (_sdtx_vertex_t*) _sdtx_malloc(vbuf_size); - - ctx->commands.cap = ctx->desc.max_commands; - ctx->commands.ptr = (_sdtx_command_t*) _sdtx_malloc((size_t)ctx->commands.cap * sizeof(_sdtx_command_t)); - _sdtx_set_layer(ctx, 0); - - sg_buffer_desc vbuf_desc; - _sdtx_clear(&vbuf_desc, sizeof(vbuf_desc)); - vbuf_desc.size = vbuf_size; - vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER; - vbuf_desc.usage = SG_USAGE_STREAM; - vbuf_desc.label = "sdtx-vbuf"; - ctx->vbuf = sg_make_buffer(&vbuf_desc); - SOKOL_ASSERT(SG_INVALID_ID != ctx->vbuf.id); - - sg_pipeline_desc pip_desc; - _sdtx_clear(&pip_desc, sizeof(pip_desc)); - pip_desc.layout.buffers[0].stride = sizeof(_sdtx_vertex_t); - pip_desc.layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT2; - pip_desc.layout.attrs[1].format = SG_VERTEXFORMAT_USHORT2N; - pip_desc.layout.attrs[2].format = SG_VERTEXFORMAT_UBYTE4N; - pip_desc.shader = _sdtx.shader; - pip_desc.index_type = SG_INDEXTYPE_NONE; - pip_desc.sample_count = ctx->desc.sample_count; - pip_desc.depth.pixel_format = ctx->desc.depth_format; - pip_desc.colors[0].pixel_format = ctx->desc.color_format; - pip_desc.colors[0].blend.enabled = true; - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ONE; - pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO; - pip_desc.label = "sdtx-pipeline"; - ctx->pip = sg_make_pipeline(&pip_desc); - SOKOL_ASSERT(SG_INVALID_ID != ctx->pip.id); - - ctx->canvas_size.x = ctx->desc.canvas_width; - ctx->canvas_size.y = ctx->desc.canvas_height; - ctx->glyph_size.x = 8.0f / ctx->canvas_size.x; - ctx->glyph_size.y = 8.0f / ctx->canvas_size.y; - ctx->tab_width = (float) ctx->desc.tab_width; - ctx->color = _SDTX_DEFAULT_COLOR; - - if (!sg_add_commit_listener(_sdtx_make_commit_listener(ctx))) { - _SDTX_ERROR(ADD_COMMIT_LISTENER_FAILED); - } - sg_pop_debug_group(); -} - -static void _sdtx_destroy_context(sdtx_context ctx_id) { - _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - if (ctx) { - if (ctx->vertices.ptr) { - _sdtx_free(ctx->vertices.ptr); - ctx->vertices.ptr = 0; - ctx->vertices.cap = 0; - ctx->vertices.next = 0; - } - if (ctx->commands.ptr) { - _sdtx_free(ctx->commands.ptr); - ctx->commands.ptr = 0; - ctx->commands.cap = 0; - ctx->commands.next = 0; - } - sg_push_debug_group("sokol_debugtext"); - sg_destroy_buffer(ctx->vbuf); - sg_destroy_pipeline(ctx->pip); - sg_remove_commit_listener(_sdtx_make_commit_listener(ctx)); - sg_pop_debug_group(); - _sdtx_clear(ctx, sizeof(*ctx)); - _sdtx_pool_free_index(&_sdtx.context_pool.pool, _sdtx_slot_index(ctx_id.id)); - } -} - -static bool _sdtx_is_default_context(sdtx_context ctx_id) { - return ctx_id.id == SDTX_DEFAULT_CONTEXT.id; -} - -// ███ ███ ██ ███████ ██████ -// ████ ████ ██ ██ ██ -// ██ ████ ██ ██ ███████ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ██████ -// -// >>misc - -// unpack linear 8x8 bits-per-pixel font data into 2D byte-per-pixel texture data -static void _sdtx_unpack_font(const sdtx_font_desc_t* font_desc, uint8_t* out_pixels) { - SOKOL_ASSERT(font_desc->data.ptr); - SOKOL_ASSERT((font_desc->data.size > 0) && ((font_desc->data.size % 8) == 0)); - SOKOL_ASSERT(font_desc->first_char <= font_desc->last_char); - SOKOL_ASSERT((size_t)(((font_desc->last_char - font_desc->first_char) + 1) * 8) == font_desc->data.size); - const uint8_t* ptr = (const uint8_t*) font_desc->data.ptr; - for (int chr = font_desc->first_char; chr <= font_desc->last_char; chr++) { - for (int line = 0; line < 8; line++) { - uint8_t bits = *ptr++; - for (int x = 0; x < 8; x++) { - out_pixels[line*256*8 + chr*8 + x] = ((bits>>(7-x)) & 1) ? 0xFF : 0x00; - } - } - } -} - -static void _sdtx_setup_common(void) { - - // common printf formatting buffer - _sdtx.fmt_buf_size = (uint32_t) _sdtx.desc.printf_buf_size + 1; - _sdtx.fmt_buf = (char*) _sdtx_malloc_clear(_sdtx.fmt_buf_size); - - sg_push_debug_group("sokol-debugtext"); - - // common shader for all contexts - sg_shader_desc shd_desc; - _sdtx_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.label = "sokol-debugtext-shader"; - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - #if defined(SOKOL_GLCORE) - shd_desc.vs.source = (const char*)_sdtx_vs_source_glsl410; - shd_desc.fs.source = (const char*)_sdtx_fs_source_glsl410; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = (const char*)_sdtx_vs_source_glsl300es; - shd_desc.fs.source = (const char*)_sdtx_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_sdtx_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_sdtx_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_sdtx_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_sdtx_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = (const char*)_sdtx_vs_source_metal_sim; - shd_desc.fs.source = (const char*)_sdtx_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_sdtx_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_sdtx_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = (const char*)_sdtx_vs_source_wgsl; - shd_desc.fs.source = (const char*)_sdtx_fs_source_wgsl; - #else - shd_desc.vs.source = _sdtx_vs_src_dummy; - shd_desc.fs.source = _sdtx_fs_src_dummy; - #endif - _sdtx.shader = sg_make_shader(&shd_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sdtx.shader.id); - - // unpack font data - memset(_sdtx.font_pixels, 0xFF, sizeof(_sdtx.font_pixels)); - const int unpacked_font_size = (int) (sizeof(_sdtx.font_pixels) / SDTX_MAX_FONTS); - for (int i = 0; i < SDTX_MAX_FONTS; i++) { - if (_sdtx.desc.fonts[i].data.ptr) { - _sdtx_unpack_font(&_sdtx.desc.fonts[i], &_sdtx.font_pixels[i * unpacked_font_size]); - } - } - - // create font texture and sampler - sg_image_desc img_desc; - _sdtx_clear(&img_desc, sizeof(img_desc)); - img_desc.width = 256 * 8; - img_desc.height = SDTX_MAX_FONTS * 8; - img_desc.pixel_format = SG_PIXELFORMAT_R8; - img_desc.data.subimage[0][0] = SG_RANGE(_sdtx.font_pixels); - img_desc.label = "sdtx-font-texture"; - _sdtx.font_img = sg_make_image(&img_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sdtx.font_img.id); - - sg_sampler_desc smp_desc; - _sdtx_clear(&smp_desc, sizeof(smp_desc)); - smp_desc.min_filter = SG_FILTER_NEAREST; - smp_desc.mag_filter = SG_FILTER_NEAREST; - smp_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; - smp_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; - smp_desc.label = "sdtx-font-sampler"; - _sdtx.font_smp = sg_make_sampler(&smp_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sdtx.font_smp.id); - - sg_pop_debug_group(); -} - -static void _sdtx_discard_common(void) { - sg_push_debug_group("sokol-debugtext"); - sg_destroy_sampler(_sdtx.font_smp); - sg_destroy_image(_sdtx.font_img); - sg_destroy_shader(_sdtx.shader); - if (_sdtx.fmt_buf) { - _sdtx_free(_sdtx.fmt_buf); - _sdtx.fmt_buf = 0; - } - sg_pop_debug_group(); -} - -static uint32_t _sdtx_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return (uint32_t)(((uint32_t)a<<24)|((uint32_t)b<<16)|((uint32_t)g<<8)|r); -} - -static float _sdtx_clamp(float v, float lo, float hi) { - if (v < lo) return lo; - else if (v > hi) return hi; - else return v; -} - -static uint32_t _sdtx_pack_rgbaf(float r, float g, float b, float a) { - uint8_t r_u8 = (uint8_t) (_sdtx_clamp(r, 0.0f, 1.0f) * 255.0f); - uint8_t g_u8 = (uint8_t) (_sdtx_clamp(g, 0.0f, 1.0f) * 255.0f); - uint8_t b_u8 = (uint8_t) (_sdtx_clamp(b, 0.0f, 1.0f) * 255.0f); - uint8_t a_u8 = (uint8_t) (_sdtx_clamp(a, 0.0f, 1.0f) * 255.0f); - return _sdtx_pack_rgbab(r_u8, g_u8, b_u8, a_u8); -} - -static void _sdtx_ctrl_char(_sdtx_context_t* ctx, uint8_t c) { - switch (c) { - case '\r': - ctx->pos.x = 0.0f; - break; - case '\n': - ctx->pos.x = 0.0f; - ctx->pos.y += 1.0f; - break; - case '\t': - ctx->pos.x = (ctx->pos.x - fmodf(ctx->pos.x, ctx->tab_width)) + ctx->tab_width; - break; - case ' ': - ctx->pos.x += 1.0f; - break; - } -} - -static _sdtx_vertex_t* _sdtx_next_vertex(_sdtx_context_t* ctx) { - if ((ctx->vertices.next + 6) <= ctx->vertices.cap) { - _sdtx_vertex_t* vx = &ctx->vertices.ptr[ctx->vertices.next]; - ctx->vertices.next += 6; - return vx; - } else { - return 0; - } -} - -static _sdtx_command_t* _sdtx_cur_command(_sdtx_context_t* ctx) { - if (ctx->commands.next > 0) { - return &ctx->commands.ptr[ctx->commands.next - 1]; - } else { - return 0; - } -} - -static _sdtx_command_t* _sdtx_next_command(_sdtx_context_t* ctx) { - if (ctx->commands.next < ctx->commands.cap) { - return &ctx->commands.ptr[ctx->commands.next++]; - } else { - _SDTX_ERROR(COMMAND_BUFFER_FULL); - return 0; - } -} - -static void _sdtx_set_layer(_sdtx_context_t* ctx, int layer_id) { - ctx->cur_layer_id = layer_id; - _sdtx_command_t* cur_cmd = _sdtx_cur_command(ctx); - if (cur_cmd) { - if ((cur_cmd->num_vertices == 0) || (cur_cmd->layer_id == layer_id)) { - // no vertices recorded in current draw command, or layer hasn't changed, can just reuse this - cur_cmd->layer_id = layer_id; - } else { - // layer has changed, need to start a new draw command - _sdtx_command_t* next_cmd = _sdtx_next_command(ctx); - if (next_cmd) { - next_cmd->layer_id = layer_id; - next_cmd->first_vertex = cur_cmd->first_vertex + cur_cmd->num_vertices; - next_cmd->num_vertices = 0; - } - } - } else { - // first draw command in frame - _sdtx_command_t* next_cmd = _sdtx_next_command(ctx); - if (next_cmd) { - next_cmd->layer_id = layer_id; - next_cmd->first_vertex = 0; - next_cmd->num_vertices = 0; - } - } -} - -static void _sdtx_render_char(_sdtx_context_t* ctx, uint8_t c) { - _sdtx_vertex_t* vx = _sdtx_next_vertex(ctx); - _sdtx_command_t* cmd = _sdtx_cur_command(ctx); - if (vx && cmd) { - // update vertex count in current draw command - cmd->num_vertices += 6; - - const float x0 = (ctx->origin.x + ctx->pos.x) * ctx->glyph_size.x; - const float y0 = (ctx->origin.y + ctx->pos.y) * ctx->glyph_size.y; - const float x1 = x0 + ctx->glyph_size.x; - const float y1 = y0 + ctx->glyph_size.y; - - // glyph width and height in font texture space - // NOTE: the '+1' and '-2' fixes texture bleeding into the neighboring font texture cell - const uint16_t uvw = 0x10000 / 0x100; - const uint16_t uvh = 0x10000 / SDTX_MAX_FONTS; - const uint16_t u0 = (((uint16_t)c) * uvw) + 1; - const uint16_t v0 = (((uint16_t)ctx->cur_font) * uvh) + 1; - uint16_t u1 = (u0 + uvw) - 2; - uint16_t v1 = (v0 + uvh) - 2; - const uint32_t color = ctx->color; - - // write 6 vertices - vx->x=x0; vx->y=y0; vx->u = u0; vx->v = v0; vx->color = color; vx++; - vx->x=x1; vx->y=y0; vx->u = u1; vx->v = v0; vx->color = color; vx++; - vx->x=x1; vx->y=y1; vx->u = u1; vx->v = v1; vx->color = color; vx++; - - vx->x=x0; vx->y=y0; vx->u = u0; vx->v = v0; vx->color = color; vx++; - vx->x=x1; vx->y=y1; vx->u = u1; vx->v = v1; vx->color = color; vx++; - vx->x=x0; vx->y=y1; vx->u = u0; vx->v = v1; vx->color = color; vx++; - } - ctx->pos.x += 1.0f; -} - -static void _sdtx_put_char(_sdtx_context_t* ctx, char c) { - uint8_t c_u8 = (uint8_t)c; - if (c_u8 <= 32) { - _sdtx_ctrl_char(ctx, c_u8); - } else { - _sdtx_render_char(ctx, c_u8); - } -} - -SOKOL_API_IMPL void _sdtx_draw_layer(_sdtx_context_t* ctx, int layer_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(ctx); - if ((ctx->vertices.next > 0) && (ctx->commands.next > 0)) { - sg_push_debug_group("sokol-debugtext"); - - if (ctx->update_frame_id != ctx->frame_id) { - ctx->update_frame_id = ctx->frame_id; - const sg_range range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sdtx_vertex_t) }; - sg_update_buffer(ctx->vbuf, &range); - } - - sg_apply_pipeline(ctx->pip); - sg_bindings bindings; - _sdtx_clear(&bindings, sizeof(bindings)); - bindings.vertex_buffers[0] = ctx->vbuf; - bindings.fs.images[0] = _sdtx.font_img; - bindings.fs.samplers[0] = _sdtx.font_smp; - sg_apply_bindings(&bindings); - for (int cmd_index = 0; cmd_index < ctx->commands.next; cmd_index++) { - const _sdtx_command_t* cmd = &ctx->commands.ptr[cmd_index]; - if (cmd->layer_id != layer_id) { - continue; - } - SOKOL_ASSERT((cmd->num_vertices % 6) == 0); - sg_draw(cmd->first_vertex, cmd->num_vertices, 1); - } - sg_pop_debug_group(); - } -} - - -static sdtx_desc_t _sdtx_desc_defaults(const sdtx_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sdtx_desc_t res = *desc; - res.context_pool_size = _sdtx_def(res.context_pool_size, _SDTX_DEFAULT_CONTEXT_POOL_SIZE); - res.printf_buf_size = _sdtx_def(res.printf_buf_size, _SDTX_DEFAULT_PRINTF_BUF_SIZE); - for (int i = 0; i < SDTX_MAX_FONTS; i++) { - if (res.fonts[i].data.ptr) { - res.fonts[i].last_char = _sdtx_def(res.fonts[i].last_char, 255); - } - } - res.context = _sdtx_context_desc_defaults(&res.context); - SOKOL_ASSERT(res.context_pool_size > 0); - SOKOL_ASSERT(res.printf_buf_size > 0); - SOKOL_ASSERT(res.context.char_buf_size > 0); - return res; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void sdtx_setup(const sdtx_desc_t* desc) { - SOKOL_ASSERT(desc); - _sdtx_clear(&_sdtx, sizeof(_sdtx)); - _sdtx.init_cookie = _SDTX_INIT_COOKIE; - _sdtx.desc = _sdtx_desc_defaults(desc); - _sdtx_setup_context_pool(&_sdtx.desc); - _sdtx_setup_common(); - _sdtx.def_ctx_id = sdtx_make_context(&_sdtx.desc.context); - SOKOL_ASSERT(SDTX_DEFAULT_CONTEXT.id == _sdtx.def_ctx_id.id); - sdtx_set_context(_sdtx.def_ctx_id); -} - -SOKOL_API_IMPL void sdtx_shutdown(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - for (int i = 0; i < _sdtx.context_pool.pool.size; i++) { - _sdtx_context_t* ctx = &_sdtx.context_pool.contexts[i]; - _sdtx_destroy_context(_sdtx_make_ctx_id(ctx->slot.id)); - } - _sdtx_discard_common(); - _sdtx_discard_context_pool(); - _sdtx.init_cookie = 0; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_kc853(void) { - sdtx_font_desc_t desc = { { _sdtx_font_kc853, sizeof(_sdtx_font_kc853) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_kc854(void) { - sdtx_font_desc_t desc = { { _sdtx_font_kc854, sizeof(_sdtx_font_kc854) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_z1013(void) { - sdtx_font_desc_t desc = { { _sdtx_font_z1013, sizeof(_sdtx_font_z1013) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_cpc(void) { - sdtx_font_desc_t desc = { { _sdtx_font_cpc, sizeof(_sdtx_font_cpc) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_c64(void) { - sdtx_font_desc_t desc = { { _sdtx_font_c64, sizeof(_sdtx_font_c64) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_font_desc_t sdtx_font_oric(void) { - sdtx_font_desc_t desc = { { _sdtx_font_oric, sizeof(_sdtx_font_oric) }, 0, 255 }; - return desc; -} - -SOKOL_API_IMPL sdtx_context sdtx_make_context(const sdtx_context_desc_t* desc) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(desc); - sdtx_context ctx_id = _sdtx_alloc_context(); - if (ctx_id.id != SG_INVALID_ID) { - _sdtx_init_context(ctx_id, desc); - } else { - _SDTX_ERROR(CONTEXT_POOL_EXHAUSTED); - } - return ctx_id; -} - -SOKOL_API_IMPL void sdtx_destroy_context(sdtx_context ctx_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - if (_sdtx_is_default_context(ctx_id)) { - _SDTX_ERROR(CANNOT_DESTROY_DEFAULT_CONTEXT); - return; - } - _sdtx_destroy_context(ctx_id); - // re-validate the current context pointer (this will return a nullptr - // if we just destroyed the current context) - _sdtx.cur_ctx = _sdtx_lookup_context(_sdtx.cur_ctx_id.id); -} - -SOKOL_API_IMPL void sdtx_set_context(sdtx_context ctx_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - if (_sdtx_is_default_context(ctx_id)) { - _sdtx.cur_ctx_id = _sdtx.def_ctx_id; - } else { - _sdtx.cur_ctx_id = ctx_id; - } - // this may return a nullptr if the ctx_id handle is invalid - _sdtx.cur_ctx = _sdtx_lookup_context(_sdtx.cur_ctx_id.id); -} - -SOKOL_API_IMPL sdtx_context sdtx_get_context(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - return _sdtx.cur_ctx_id; -} - -SOKOL_API_IMPL sdtx_context sdtx_default_context(void) { - return SDTX_DEFAULT_CONTEXT; -} - -SOKOL_API_IMPL void sdtx_layer(int layer_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - _sdtx_set_layer(ctx, layer_id); - } -} - -SOKOL_API_IMPL void sdtx_font(int font_index) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT((font_index >= 0) && (font_index < SDTX_MAX_FONTS)); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->cur_font = font_index; - } -} - -SOKOL_API_IMPL void sdtx_canvas(float w, float h) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(!isnan(w)); - SOKOL_ASSERT(!isnan(h)); - SOKOL_ASSERT((w > 0.0f) && (h > 0.0f)); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->canvas_size.x = w; - ctx->canvas_size.y = h; - ctx->glyph_size.x = (8.0f / ctx->canvas_size.x); - ctx->glyph_size.y = (8.0f / ctx->canvas_size.y); - ctx->origin.x = 0.0f; - ctx->origin.y = 0.0f; - ctx->pos.x = 0.0f; - ctx->pos.y = 0.0f; - } -} - -SOKOL_API_IMPL void sdtx_origin(float x, float y) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->origin.x = x; - ctx->origin.y = y; - } -} - -SOKOL_API_IMPL void sdtx_home(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x = 0.0f; - ctx->pos.y = 0.0f; - } -} - -SOKOL_API_IMPL void sdtx_pos(float x, float y) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x = x; - ctx->pos.y = y; - } -} - -SOKOL_API_IMPL void sdtx_pos_x(float x) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x = x; - } -} - -SOKOL_API_IMPL void sdtx_pos_y(float y) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.y = y; - } -} - -SOKOL_API_IMPL void sdtx_move(float dx, float dy) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x += dx; - ctx->pos.y += dy; - } -} - -SOKOL_API_IMPL void sdtx_move_x(float dx) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x += dx; - } -} - -SOKOL_API_IMPL void sdtx_move_y(float dy) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.y += dy; - } -} - -SOKOL_API_IMPL void sdtx_crlf(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->pos.x = 0.0f; - ctx->pos.y += 1.0f; - } -} - -SOKOL_API_IMPL void sdtx_color3b(uint8_t r, uint8_t g, uint8_t b) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = _sdtx_pack_rgbab(r, g, b, 255); - } -} - -SOKOL_API_IMPL void sdtx_color3f(float r, float g, float b) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = _sdtx_pack_rgbaf(r, g, b, 1.0f); - } -} - -SOKOL_API_IMPL void sdtx_color4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = _sdtx_pack_rgbab(r, g, b, a); - } -} - -SOKOL_API_IMPL void sdtx_color4f(float r, float g, float b, float a) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = _sdtx_pack_rgbaf(r, g, b, a); - } -} - -SOKOL_API_IMPL void sdtx_color1i(uint32_t rgba) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - ctx->color = rgba; - } -} - -SOKOL_DEBUGTEXT_API_DECL void sdtx_putc(char chr) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - _sdtx_put_char(ctx, chr); - } -} - -SOKOL_DEBUGTEXT_API_DECL void sdtx_puts(const char* str) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - char chr; - while (0 != (chr = *str++)) { - _sdtx_put_char(ctx, chr); - } - } -} - -SOKOL_DEBUGTEXT_API_DECL void sdtx_putr(const char* str, int len) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - for (int i = 0; i < len; i++) { - char chr = str[i]; - if (0 == chr) { - break; - } - _sdtx_put_char(ctx, chr); - } - } -} - -SOKOL_DEBUGTEXT_API_DECL int sdtx_vprintf(const char* fmt, va_list args) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(_sdtx.fmt_buf && (_sdtx.fmt_buf_size >= 2)); - int res = SOKOL_VSNPRINTF(_sdtx.fmt_buf, _sdtx.fmt_buf_size, fmt, args); - // make sure we're 0-terminated in case we're on an old MSVC - _sdtx.fmt_buf[_sdtx.fmt_buf_size-1] = 0; - sdtx_puts(_sdtx.fmt_buf); - return res; -} - -SOKOL_DEBUGTEXT_API_DECL int sdtx_printf(const char* fmt, ...) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - SOKOL_ASSERT(_sdtx.fmt_buf && (_sdtx.fmt_buf_size >= 2)); - va_list args; - va_start(args, fmt); - int res = SOKOL_VSNPRINTF(_sdtx.fmt_buf, _sdtx.fmt_buf_size, fmt, args); - va_end(args); - // make sure we're 0-terminated in case we're on an old MSVC - _sdtx.fmt_buf[_sdtx.fmt_buf_size-1] = 0; - sdtx_puts(_sdtx.fmt_buf); - return res; -} - -SOKOL_API_IMPL void sdtx_draw(void) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - _sdtx_draw_layer(ctx, 0); - } -} - -SOKOL_API_IMPL void sdtx_context_draw(sdtx_context ctx_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - if (ctx) { - _sdtx_draw_layer(ctx, 0); - } -} - -SOKOL_API_IMPL void sdtx_draw_layer(int layer_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx.cur_ctx; - if (ctx) { - _sdtx_draw_layer(ctx, layer_id); - } -} - -SOKOL_API_IMPL void sdtx_context_draw_layer(sdtx_context ctx_id, int layer_id) { - SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); - _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); - if (ctx) { - _sdtx_draw_layer(ctx, layer_id); - } -} -#endif // SOKOL_DEBUGTEXT_IMPL diff --git a/source/thirdparty/sokol/util/sokol_fontstash.h b/source/thirdparty/sokol/util/sokol_fontstash.h deleted file mode 100644 index 861241e7..00000000 --- a/source/thirdparty/sokol/util/sokol_fontstash.h +++ /dev/null @@ -1,1789 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_FONTSTASH_IMPL) -#define SOKOL_FONTSTASH_IMPL -#endif -#ifndef SOKOL_FONTSTASH_INCLUDED -/* - sokol_fontstash.h -- renderer for https://github.com/memononen/fontstash - on top of sokol_gl.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_FONTSTASH_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 - - ...optionally provide the following macros to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_FONTSTASH_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_FONTSTASH_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - - Include the following headers before including sokol_fontstash.h: - - sokol_gfx.h - - Additionally include the following headers for including the sokol_fontstash.h - implementation: - - sokol_gl.h - - HOW TO - ====== - --- First initialize sokol-gfx and sokol-gl as usual: - - sg_setup(&(sg_desc){...}); - sgl_setup(&(sgl_desc){...}); - - --- Create at least one fontstash context with sfons_create() (this replaces - glfonsCreate() from fontstash.h's example GL renderer: - - FONScontext* ctx = sfons_create(&(sfons_desc_t){ - .width = atlas_width, - .height = atlas_height, - }); - - Each FONScontext manages one font atlas texture which can hold rasterized - glyphs for multiple fonts. - - --- From here on, use fontstash.h's functions "as usual" to add TTF - font data and draw text. Note that (just like with sokol-gl), text - rendering can happen anywhere in the frame, not only inside - a sokol-gfx rendering pass. - - --- You can use the helper function - - uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) - - To convert a 0..255 RGBA color into a packed uint32_t color value - expected by fontstash.h. - - --- Once per frame before calling sgl_draw(), call: - - sfons_flush(FONScontext* ctx) - - ...this will update the dynamic sokol-gfx texture with the latest font - atlas content. - - --- To actually render the text (and any other sokol-gl draw commands), - call sgl_draw() inside a sokol-gfx frame. - - --- NOTE that you can mix fontstash.h calls with sokol-gl calls to mix - text rendering with sokol-gl rendering. You can also use - sokol-gl's matrix stack to position fontstash.h text in 3D. - - --- finally on application shutdown, call: - - sfons_destroy(FONScontext* ctx) - - before sgl_shutdown() and sg_shutdown() - - - WHAT HAPPENS UNDER THE HOOD: - ============================ - - FONScontext* sfons_create(const sfons_desc_t* desc) - - creates a sokol-gfx shader compatible with sokol-gl - - creates an sgl_pipeline object with alpha-blending using - this shader - - creates a 1-byte-per-pixel font atlas texture via sokol-gfx - (pixel format SG_PIXELFORMAT_R8) - - fonsDrawText(): - - this will call the following sequence of sokol-gl functions: - - sgl_enable_texture(); - sgl_texture(...); - sgl_push_pipeline(); - sgl_load_pipeline(...); - sgl_begin_triangles(); - for each vertex: - sgl_v2f_t2f_c1i(...); - sgl_end(); - sgl_pop_pipeline(); - sgl_disable_texture(); - - - note that sokol-gl will merge several sgl_*_begin/sgl_end pairs - into a single draw call if no relevant state has changed, typically - all calls to fonsDrawText() will be merged into a single draw call - as long as all calls use the same FONScontext - - sfons_flush(FONScontext* ctx): - - this will call sg_update_image() on the font atlas texture - if fontstash.h has added any rasterized glyphs since the last - frame - - sfons_destroy(FONScontext* ctx): - - destroy the font atlas texture, sgl_pipeline and sg_shader objects - - - 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); - } - - ... - FONScontext* fons_context = sfons_create(&(sfons_desc_t){ - ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ..., - } - }); - ... - - If no overrides are provided, malloc and free will be used. Please - note that this doesn't affect any memory allocation performed - in fontstash.h (unfortunately those are hardwired to malloc/free). - - 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. -*/ -#define SOKOL_FONTSTASH_INCLUDED (1) -#include -#include -#include // size_t - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_fontstash.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_FONTSTASH_API_DECL) -#define SOKOL_FONTSTASH_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_FONTSTASH_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_FONTSTASH_IMPL) -#define SOKOL_FONTSTASH_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_FONTSTASH_API_DECL __declspec(dllimport) -#else -#define SOKOL_FONTSTASH_API_DECL extern -#endif -#endif -#ifdef __cplusplus -extern "C" { -#endif - -/* - sfonst_allocator_t - - Used in sfons_desc_t to provide custom memory-alloc and -free functions - to sokol_fontstash.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). - - NOTE that this does not affect memory allocation calls inside - fontstash.h -*/ -typedef struct sfons_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sfons_allocator_t; - -typedef struct sfons_desc_t { - int width; // initial width of font atlas texture (default: 512, must be power of 2) - int height; // initial height of font atlas texture (default: 512, must be power of 2) - sfons_allocator_t allocator; // optional memory allocation overrides -} sfons_desc_t; - -SOKOL_FONTSTASH_API_DECL FONScontext* sfons_create(const sfons_desc_t* desc); -SOKOL_FONTSTASH_API_DECL void sfons_destroy(FONScontext* ctx); -SOKOL_FONTSTASH_API_DECL void sfons_flush(FONScontext* ctx); -SOKOL_FONTSTASH_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); - -#ifdef __cplusplus -} /* extern "C" */ -#endif -#endif /* SOKOL_FONTSTASH_INCLUDED */ - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_FONTSTASH_IMPL -#define SOKOL_FONTSTASH_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sfons_desc_t.allocator to override memory allocation functions" -#endif - -#include // memset, memcpy -#include // malloc, free - -#if !defined(SOKOL_GL_INCLUDED) -#error "Please include sokol_gl.h before sokol_fontstash.h" -#endif -#if !defined(FONS_H) -#error "Please include fontstash.h before sokol_fontstash.h" -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif -#ifndef _SOKOL_UNUSED - #define _SOKOL_UNUSED(x) (void)(x) -#endif - -#if defined(SOKOL_GLCORE) -/* - Embedded source code compiled with: - - sokol-shdc -i sfons.glsl -o sfons.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b - - (not that for Metal and D3D11 byte code, sokol-shdc must be run - on macOS and Windows) - - @vs vs - uniform vs_params { - uniform mat4 mvp; - uniform mat4 tm; - }; - in vec4 position; - in vec2 texcoord0; - in vec4 color0; - in float psize; - out vec4 uv; - out vec4 color; - void main() { - gl_Position = mvp * position; - #ifndef SOKOL_WGSL - gl_PointSize = psize; - #endif - uv = tm * vec4(texcoord0, 0.0, 1.0); - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - in vec4 uv; - in vec4 color; - out vec4 frag_color; - void main() { - frag_color = vec4(1.0, 1.0, 1.0, texture(sampler2D(tex, smp), uv.xy).r) * color; - } - @end - - @program sfontstash vs fs -*/ -static const uint8_t _sfons_vs_source_glsl410[520] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, - 0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65, - 0x63,0x34,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f, - 0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76, - 0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6c, - 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, - 0x20,0x31,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, - 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, - 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53, - 0x69,0x7a,0x65,0x20,0x3d,0x20,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x75,0x76,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73, - 0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x37, - 0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sfons_fs_source_glsl410[245] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, - 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, - 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67, - 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x31,0x2e, - 0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76, - 0x2e,0x78,0x79,0x29,0x2e,0x78,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_GLES3) -static const uint8_t _sfons_vs_source_glsl300es[481] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, - 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, - 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x20,0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x20,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74, - 0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79, - 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32, - 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b, - 0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b, - 0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d, - 0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20, - 0x2a,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x70, - 0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x6d, - 0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d, - 0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x37,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65, - 0x63,0x34,0x28,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e, - 0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a, - 0x00, -}; -static const uint8_t _sfons_fs_source_glsl300es[276] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, - 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x75, - 0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, - 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x31,0x2e,0x30, - 0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x2e, - 0x78,0x79,0x29,0x2e,0x78,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _sfons_vs_bytecode_metal_macos[3317] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf5,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x76,0x25,0x5f,0x37,0x22,0xd0,0x3f, - 0x64,0xef,0xff,0xc3,0x45,0x1a,0x3d,0xb7,0x5e,0x83,0x13,0x96,0xd3,0x09,0xec,0x53, - 0x25,0xd5,0x7e,0x0c,0xed,0xb9,0x58,0x34,0x02,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x40,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x2a,0x00,0x04,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x70,0x73,0x69,0x7a,0x65,0x00,0x03,0x80,0x56,0x41,0x54, - 0x59,0x06,0x00,0x04,0x00,0x06,0x04,0x06,0x03,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, - 0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00, - 0x00,0xc4,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00, - 0x00,0xee,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00, - 0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84, - 0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b, - 0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90, - 0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8, - 0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x81,0x00,0x00, - 0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77, - 0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8, - 0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87, - 0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c, - 0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8, - 0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18, - 0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc, - 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21, - 0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e, - 0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06, - 0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77, - 0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68, - 0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87, - 0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d, - 0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36, - 0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0, - 0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6, - 0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61, - 0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07, - 0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, - 0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e, - 0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea, - 0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c, - 0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea, - 0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1, - 0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x18,0x42, - 0x01,0x2c,0x40,0x05,0x00,0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40, - 0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, - 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, - 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00,0xc3,0x08,0x04,0x60,0x89,0x10,0x02, - 0x18,0x46,0x10,0x80,0x24,0x08,0x33,0x51,0xf3,0x40,0x0f,0xf2,0x50,0x0f,0xe3,0x40, - 0x0f,0x6e,0xd0,0x0e,0xe5,0x40,0x0f,0xe1,0xc0,0x0e,0x7a,0xa0,0x07,0xed,0x10,0x0e, - 0xf4,0x20,0x0f,0xe9,0x80,0x0f,0x28,0x20,0x07,0x49,0x53,0x44,0x09,0x93,0x5f,0x49, - 0xff,0x03,0x44,0x00,0x23,0x21,0xa1,0x94,0x41,0x04,0x43,0x28,0x86,0x08,0x23,0x80, - 0x43,0x68,0x20,0x60,0x8e,0x00,0x0c,0x52,0x60,0xcd,0x11,0x80,0xc2,0x20,0x42,0x20, - 0x0c,0x23,0x10,0xcb,0x08,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, - 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, - 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, - 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, - 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, - 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, - 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, - 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0xc8,0x02,0x01,0x00,0x00,0x0b,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18, - 0x50,0x08,0x65,0x50,0x80,0x02,0x05,0x51,0x20,0xd4,0x46,0x00,0x88,0x8d,0x25,0x34, - 0x01,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x02,0x01,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32, - 0x28,0x00,0xb3,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x2c,0x81,0x22,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25, - 0x58,0x90,0x45,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82, - 0x45,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04, - 0x65,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c, - 0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba, - 0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61, - 0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde, - 0xc2,0xe8,0x68,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95, - 0x51,0xa8,0xb3,0x1b,0xc2,0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9, - 0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0x61,0x31,0xf6,0xc6,0xf6,0x26, - 0x37,0x84,0x51,0x1e,0xc5,0x52,0x22,0x45,0x52,0x26,0xe5,0x22,0x13,0x96,0x26,0xe7, - 0x02,0xf7,0x36,0x97,0x46,0x97,0xf6,0xe6,0xc6,0xe5,0x8c,0xed,0x0b,0xea,0x6d,0x2e, - 0x8d,0x2e,0xed,0xcd,0x6d,0x88,0xa2,0x64,0x4a,0xa4,0x48,0xca,0xa4,0x68,0x74,0xc2, - 0xd2,0xe4,0x5c,0xe0,0xde,0xd2,0xdc,0xe8,0xbe,0xe6,0xd2,0xf4,0xca,0x58,0x98,0xb1, - 0xbd,0x85,0xd1,0x91,0x39,0x63,0xfb,0x82,0x7a,0x4b,0x73,0xa3,0x9b,0x4a,0xd3,0x2b, - 0x1b,0xa2,0x28,0x9c,0x12,0x29,0x9d,0x32,0x29,0xde,0x10,0x44,0xa9,0x14,0x4c,0xd9, - 0x94,0x8f,0x50,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0x57,0x9a,0x1b, - 0x5c,0x1d,0x1d,0xa5,0xb0,0x34,0x39,0x17,0xb6,0xb7,0xb1,0x30,0xba,0xb4,0x37,0xb7, - 0xaf,0x34,0x37,0xb2,0x32,0x3c,0x7a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64, - 0x28,0x5f,0x5f,0x61,0x69,0x72,0x5f,0x70,0x6c,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64, - 0x65,0x72,0x5f,0x5f,0x29,0x44,0xe0,0xde,0xe6,0xd2,0xe8,0xd2,0xde,0xdc,0x86,0x50, - 0x8b,0xa0,0x84,0x81,0x22,0x06,0x8b,0xb0,0x04,0xca,0x18,0x28,0x91,0x22,0x29,0x93, - 0x42,0x06,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x98,0xd0,0x95,0xe1,0x8d,0xbd,0xbd, - 0xc9,0x91,0xc1,0x0c,0xa1,0x96,0x40,0x09,0x03,0x45,0x0c,0x96,0x60,0x09,0x94,0x31, - 0x50,0x22,0xc5,0x0c,0x94,0x49,0x39,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43, - 0xa8,0x65,0x50,0xc2,0x40,0x11,0x83,0x65,0x58,0x02,0x65,0x0c,0x94,0x48,0x91,0x94, - 0x49,0x49,0x03,0x16,0x70,0x73,0x69,0x7a,0x65,0x43,0xa8,0xc5,0x50,0xc2,0x40,0x11, - 0x83,0xc5,0x58,0x02,0x65,0x0c,0x94,0x48,0xe9,0x94,0x49,0x59,0x03,0x2a,0x61,0x69, - 0x72,0x2e,0x62,0x75,0x66,0x66,0x65,0x72,0x7c,0xc2,0xd2,0xe4,0x5c,0xc4,0xea,0xcc, - 0xcc,0xca,0xe4,0xbe,0xe6,0xd2,0xf4,0xca,0x88,0x84,0xa5,0xc9,0xb9,0xc8,0x95,0x85, - 0x91,0x91,0x0a,0x4b,0x93,0x73,0x99,0xa3,0x93,0xab,0x1b,0xa3,0xfb,0xa2,0xcb,0x83, - 0x2b,0xfb,0x4a,0x73,0x33,0x7b,0x23,0x62,0xc6,0xf6,0x16,0x46,0x47,0x83,0x47,0xc3, - 0xa1,0xcd,0x0e,0x8e,0x02,0x5d,0xdb,0x10,0x6a,0x11,0x16,0x62,0x11,0x94,0x38,0x50, - 0xe4,0x60,0x21,0x16,0x62,0x11,0x94,0x38,0x50,0xe6,0x80,0x51,0x58,0x9a,0x9c,0x4b, - 0x98,0xdc,0xd9,0x17,0x5d,0x1e,0x5c,0xd9,0xd7,0x5c,0x9a,0x5e,0x19,0xaf,0xb0,0x34, - 0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x30,0xb6,0xb4,0x33,0xb7, - 0xaf,0xb9,0x34,0xbd,0x32,0x26,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x1c, - 0xbe,0x62,0x72,0x86,0x90,0xc1,0x52,0x28,0x6d,0xa0,0xb8,0xc1,0x72,0x28,0x62,0xb0, - 0x08,0x4b,0xa0,0xbc,0x81,0x02,0x07,0x0a,0x1d,0x28,0x75,0xb0,0x1c,0x8a,0x1d,0x2c, - 0x89,0x12,0x29,0x77,0xa0,0x4c,0x0a,0x1e,0x0c,0x51,0x94,0x32,0x50,0xd0,0x40,0x51, - 0x03,0x85,0x0d,0x94,0x3c,0x18,0x62,0x24,0x80,0x02,0x06,0x8a,0x1e,0xf0,0x79,0x6b, - 0x73,0x4b,0x83,0x7b,0xa3,0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3,0x33,0x95, - 0xd6,0x06,0xc7,0x56,0x06,0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34,0x44,0x50, - 0xfa,0x60,0x88,0xa1,0xf0,0x81,0xe2,0x07,0x8d,0x32,0xc4,0x50,0xfe,0x40,0xf9,0x83, - 0x46,0x19,0x11,0xb1,0x03,0x3b,0xd8,0x43,0x3b,0xb8,0x41,0x3b,0xbc,0x03,0x39,0xd4, - 0x03,0x3b,0x94,0x83,0x1b,0x98,0x03,0x3b,0x84,0xc3,0x39,0xcc,0xc3,0x14,0x21,0x18, - 0x46,0x28,0xec,0xc0,0x0e,0xf6,0xd0,0x0e,0x6e,0x90,0x0e,0xe4,0x50,0x0e,0xee,0x40, - 0x0f,0x53,0x82,0x62,0xc4,0x12,0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f, - 0xf3,0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02,0x63,0x04,0x15,0x0e,0xe9,0x20,0x0f,0x6e, - 0xc0,0x0e,0xe1,0xe0,0x0e,0xe7,0x50,0x0f,0xe1,0x70,0x0e,0xe5,0xf0,0x0b,0xf6,0x50, - 0x0e,0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25,0x40,0x46,0x4c,0xe1,0x90,0x0e, - 0xf2,0xe0,0x06,0xe3,0xf0,0x0e,0xed,0x00,0x0f,0xe9,0xc0,0x0e,0xe5,0xf0,0x0b,0xef, - 0x00,0x0f,0xf4,0x90,0x0e,0xef,0xe0,0x0e,0xf3,0x30,0x65,0x50,0x18,0x67,0x84,0x12, - 0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f,0xf4,0x50,0x0e,0xf8,0x30,0x25, - 0xd8,0x03,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80, - 0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80, - 0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80, - 0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88, - 0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78, - 0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03, - 0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f, - 0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c, - 0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39, - 0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60, - 0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87, - 0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e, - 0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c, - 0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6, - 0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94, - 0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03, - 0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07, - 0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f, - 0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33, - 0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc, - 0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c, - 0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78, - 0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca, - 0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21, - 0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43, - 0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87, - 0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c, - 0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e, - 0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c, - 0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c, - 0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00, - 0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x3e,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0xf4,0xc6,0x22, - 0x86,0x61,0x18,0xc6,0x22,0x04,0x41,0x10,0xc6,0x22,0x82,0x20,0x08,0xa8,0x95,0x40, - 0x19,0x14,0x01,0xbd,0x11,0x00,0x1a,0x33,0x00,0x24,0x66,0x00,0x28,0xcc,0x00,0x00, - 0x00,0xe3,0x15,0x4b,0x94,0x65,0x11,0x05,0x65,0x90,0x21,0x1a,0x0c,0x13,0x02,0xf9, - 0x8c,0x57,0x3c,0x55,0xd7,0x2d,0x14,0x94,0x41,0x86,0xea,0x70,0x4c,0x08,0xe4,0x63, - 0x41,0x01,0x9f,0xf1,0x0a,0x4a,0x13,0x03,0x31,0x70,0x28,0x28,0x83,0x0c,0x1a,0x43, - 0x99,0x10,0xc8,0xc7,0x8a,0x00,0x3e,0xe3,0x15,0xd9,0x77,0x06,0x67,0x40,0x51,0x50, - 0x06,0x19,0xbe,0x48,0x33,0x21,0x90,0x8f,0x15,0x01,0x7c,0xc6,0x2b,0x3c,0x32,0x68, - 0x03,0x36,0x20,0x03,0x0a,0xca,0x20,0xc3,0x18,0x60,0x99,0x09,0x81,0x7c,0xc6,0x2b, - 0xc4,0x00,0x0d,0xe2,0x00,0x0e,0x3c,0x0a,0xca,0x20,0xc3,0x19,0x70,0x61,0x60,0x42, - 0x20,0x1f,0x0b,0x0a,0xf8,0x8c,0x57,0x9c,0x41,0x1b,0xd8,0x41,0x1d,0x88,0x01,0x05, - 0xc5,0x86,0x00,0x3e,0xb3,0x0d,0x61,0x10,0x00,0xb3,0x0d,0x41,0x1b,0x04,0xb3,0x0d, - 0xc1,0x23,0xcc,0x36,0x04,0x6e,0x30,0x64,0x10,0x10,0x03,0x00,0x00,0x09,0x00,0x00, - 0x00,0x5b,0x86,0x20,0x00,0x85,0x2d,0x43,0x11,0x80,0xc2,0x96,0x41,0x09,0x40,0x61, - 0xcb,0xf0,0x04,0xa0,0xb0,0x65,0xa0,0x02,0x50,0xd8,0x32,0x60,0x01,0x28,0x6c,0x19, - 0xba,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sfons_fs_bytecode_metal_macos[2857] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x29,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x50,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0x38,0x3c,0x07,0x7d,0xe0,0x21,0x6b, - 0x04,0x03,0x36,0x12,0x1d,0xbc,0x24,0x12,0xc4,0x27,0xab,0xef,0x84,0x17,0xbe,0x12, - 0x8d,0xc7,0xbc,0x06,0xbc,0x98,0x53,0xdb,0x0b,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x30,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x89,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1e,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x4c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x70,0x94,0x34,0x45,0x94,0x30, - 0xf9,0xff,0x44,0x5c,0x13,0x15,0x11,0xbf,0x3d,0xfc,0xd3,0x18,0x01,0x30,0x88,0x30, - 0x04,0x17,0x49,0x53,0x44,0x09,0x93,0xff,0x4b,0x00,0xf3,0x2c,0x44,0xf4,0x4f,0x63, - 0x04,0xc0,0x20,0x42,0x21,0x94,0x42,0x84,0x40,0x0c,0x9d,0x61,0x04,0x01,0x98,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0x88,0x49,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x30,0x02,0xb1,0x8c,0x00,0x00,0x00,0x00,0x00,0x13,0xb2,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x76,0x08,0x87,0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83, - 0x38,0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78, - 0xa0,0x07,0x78,0xd0,0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90, - 0x0e,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e, - 0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76, - 0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20, - 0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30, - 0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07, - 0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71, - 0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20, - 0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f, - 0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76, - 0xd0,0x06,0xf6,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50, - 0x07,0x71,0x20,0x07,0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78, - 0xa0,0x07,0x71,0x60,0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x41,0x00,0x00,0x08,0x00, - 0x00,0x00,0x00,0x00,0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64, - 0x81,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50, - 0x10,0x65,0x40,0x70,0x2c,0xa1,0x09,0x00,0x00,0x79,0x18,0x00,0x00,0xb7,0x00,0x00, - 0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37, - 0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b, - 0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c, - 0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26, - 0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac, - 0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0, - 0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79, - 0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6, - 0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6, - 0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62, - 0x6c,0x65,0x43,0x84,0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5, - 0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99, - 0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86, - 0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59, - 0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f, - 0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c, - 0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd, - 0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08, - 0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b, - 0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c, - 0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72, - 0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x14,0xea,0xec,0x86, - 0x48,0xcb,0xf0,0x58,0xcf,0xf5,0x60,0x4f,0xf6,0x40,0x4f,0xf4,0x48,0x8f,0xc6,0xa5, - 0x6e,0xae,0x4c,0x0e,0x85,0xed,0x6d,0xcc,0x2d,0x26,0x85,0xc5,0xd8,0x1b,0xdb,0x9b, - 0xdc,0x10,0x69,0x11,0x1e,0xeb,0xe1,0x1e,0xec,0xc9,0x1e,0xe8,0x89,0x1e,0xe9,0xe9, - 0xb8,0x84,0xa5,0xc9,0xb9,0xd0,0x95,0xe1,0xd1,0xd5,0xc9,0x95,0x51,0x0a,0x4b,0x93, - 0x73,0x61,0x7b,0x1b,0x0b,0xa3,0x4b,0x7b,0x73,0xfb,0x4a,0x73,0x23,0x2b,0xc3,0xa3, - 0x12,0x96,0x26,0xe7,0x32,0x17,0xd6,0x06,0xc7,0x56,0x46,0x8c,0xae,0x0c,0x8f,0xae, - 0x4e,0xae,0x4c,0x86,0x8c,0xc7,0x8c,0xed,0x2d,0x8c,0x8e,0x05,0x64,0x2e,0xac,0x0d, - 0x8e,0xad,0xcc,0x87,0x03,0x5d,0x19,0xde,0x10,0x6a,0x21,0x9e,0xef,0x01,0x83,0x65, - 0x58,0x84,0x27,0x0c,0x1e,0xe8,0x11,0x83,0x47,0x7a,0xc6,0x80,0x4b,0x58,0x9a,0x9c, - 0xcb,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x8f,0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39, - 0x0e,0x73,0x6d,0x70,0x43,0xa4,0xe5,0x78,0xca,0xe0,0x01,0x83,0x65,0x58,0x84,0x07, - 0x7a,0xcc,0xe0,0x91,0x9e,0x33,0x18,0x82,0x3c,0xdb,0xe3,0x3d,0x64,0xf0,0xa0,0xc1, - 0x10,0x03,0x01,0x9e,0xea,0x49,0x83,0x11,0x11,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b, - 0xb4,0xc3,0x3b,0x90,0x43,0x3d,0xb0,0x43,0x39,0xb8,0x81,0x39,0xb0,0x43,0x38,0x9c, - 0xc3,0x3c,0x4c,0x11,0x82,0x61,0x84,0xc2,0x0e,0xec,0x60,0x0f,0xed,0xe0,0x06,0xe9, - 0x40,0x0e,0xe5,0xe0,0x0e,0xf4,0x30,0x25,0x28,0x46,0x2c,0xe1,0x90,0x0e,0xf2,0xe0, - 0x06,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25,0x30,0x46,0x50, - 0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xec,0x10,0x0e,0xee,0x70,0x0e,0xf5,0x10,0x0e,0xe7, - 0x50,0x0e,0xbf,0x60,0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02, - 0x64,0xc4,0x14,0x0e,0xe9,0x20,0x0f,0x6e,0x30,0x0e,0xef,0xd0,0x0e,0xf0,0x90,0x0e, - 0xec,0x50,0x0e,0xbf,0xf0,0x0e,0xf0,0x40,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x0f,0x53, - 0x06,0x85,0x71,0x46,0x30,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe6,0x20,0x0f,0xe1,0x70, - 0x0e,0xed,0x50,0x0e,0xee,0x40,0x0f,0x53,0x02,0x35,0x00,0x00,0x00,0x79,0x18,0x00, - 0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d, - 0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c, - 0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d, - 0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d, - 0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79, - 0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc, - 0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50, - 0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30, - 0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03, - 0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07, - 0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76, - 0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98, - 0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8, - 0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21, - 0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43, - 0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f, - 0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70, - 0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0, - 0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40, - 0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41, - 0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e, - 0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07, - 0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f, - 0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d, - 0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38, - 0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88, - 0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08, - 0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50, - 0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01, - 0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03, - 0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c, - 0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00, - 0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d, - 0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x16,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x14,0xc7,0x22, - 0x80,0x40,0x20,0x88,0x8d,0x00,0x8c,0x25,0x00,0x01,0xa9,0x11,0x80,0x1a,0x20,0x31, - 0x03,0x40,0x61,0x0e,0xe2,0xba,0xae,0x6a,0x06,0x80,0xc0,0x0c,0xc0,0x08,0xc0,0x18, - 0x01,0x08,0x82,0x20,0xfe,0x01,0x00,0x00,0x00,0x83,0x0c,0x0f,0x91,0x8c,0x18,0x28, - 0x42,0x80,0x39,0x4d,0x80,0x2c,0xc9,0x30,0xc8,0x70,0x04,0x8d,0x05,0x91,0x7c,0x66, - 0x1b,0x94,0x00,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sfons_vs_bytecode_metal_ios[3317] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf5,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x17,0x11,0x57,0x16,0x94,0x42,0x52, - 0xfb,0x1e,0xd0,0x32,0xfd,0x87,0x16,0xb0,0xa4,0xd0,0xc2,0x43,0xbe,0x93,0x8c,0xe0, - 0x2d,0x7a,0x5c,0x3e,0x06,0x4c,0x57,0xeb,0x4b,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x40,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x2a,0x00,0x04,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x70,0x73,0x69,0x7a,0x65,0x00,0x03,0x80,0x56,0x41,0x54, - 0x59,0x06,0x00,0x04,0x00,0x06,0x04,0x06,0x03,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, - 0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00, - 0x00,0xc0,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00, - 0x00,0xed,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00, - 0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84, - 0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b, - 0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90, - 0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8, - 0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x82,0x00,0x00, - 0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77, - 0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8, - 0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87, - 0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c, - 0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8, - 0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18, - 0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc, - 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21, - 0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e, - 0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06, - 0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77, - 0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68, - 0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87, - 0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d, - 0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36, - 0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0, - 0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6, - 0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61, - 0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07, - 0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, - 0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e, - 0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea, - 0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c, - 0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea, - 0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1, - 0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x20,0x42, - 0x01,0x24,0xc0,0x02,0x54,0x00,0x00,0x00,0x00,0x49,0x18,0x00,0x00,0x01,0x00,0x00, - 0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48, - 0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90, - 0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00,0xc3,0x08,0x04, - 0x60,0x89,0x10,0x02,0x18,0x46,0x10,0x80,0x24,0x08,0x33,0x51,0xf3,0x40,0x0f,0xf2, - 0x50,0x0f,0xe3,0x40,0x0f,0x6e,0xd0,0x0e,0xe5,0x40,0x0f,0xe1,0xc0,0x0e,0x7a,0xa0, - 0x07,0xed,0x10,0x0e,0xf4,0x20,0x0f,0xe9,0x80,0x0f,0x28,0x20,0x07,0x49,0x53,0x44, - 0x09,0x93,0x5f,0x49,0xff,0x03,0x44,0x00,0x23,0x21,0xa1,0x94,0x41,0x04,0x43,0x28, - 0x86,0x08,0x23,0x80,0x43,0x68,0x20,0x60,0x8e,0x00,0x0c,0x52,0x60,0xcd,0x11,0x80, - 0xc2,0x20,0x42,0x20,0x0c,0x23,0x10,0xcb,0x08,0x00,0x00,0x00,0x00,0x13,0xa8,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51, - 0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78, - 0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0, - 0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90, - 0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06, - 0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72, - 0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10, - 0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73, - 0x20,0x07,0x43,0x98,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x2c,0x10,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, - 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18,0x50,0x08,0x65,0x50, - 0x80,0x02,0x05,0x51,0x20,0xd4,0x46,0x00,0x88,0x8d,0x25,0x40,0x02,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x02,0x01,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2, - 0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32,0x28,0x00,0xb3,0x50, - 0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0x81,0x22,0x2c, - 0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae, - 0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06, - 0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25,0x58,0x90,0x45,0x60, - 0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82,0x45,0xe0,0x16,0x96, - 0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7, - 0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50,0x12,0x72,0x61,0x69, - 0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d, - 0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x65,0x21,0x19,0x84, - 0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95, - 0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85, - 0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d, - 0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6, - 0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79, - 0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x68,0xc8,0x84, - 0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2, - 0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61, - 0x7b,0x1b,0x73,0x8b,0x49,0x61,0x31,0xf6,0xc6,0xf6,0x26,0x37,0x84,0x51,0x1e,0xc5, - 0x52,0x22,0x45,0x52,0x26,0xe5,0x22,0x13,0x96,0x26,0xe7,0x02,0xf7,0x36,0x97,0x46, - 0x97,0xf6,0xe6,0xc6,0xe5,0x8c,0xed,0x0b,0xea,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x6d, - 0x88,0xa2,0x64,0x4a,0xa4,0x48,0xca,0xa4,0x68,0x74,0xc2,0xd2,0xe4,0x5c,0xe0,0xde, - 0xd2,0xdc,0xe8,0xbe,0xe6,0xd2,0xf4,0xca,0x58,0x98,0xb1,0xbd,0x85,0xd1,0x91,0x39, - 0x63,0xfb,0x82,0x7a,0x4b,0x73,0xa3,0x9b,0x4a,0xd3,0x2b,0x1b,0xa2,0x28,0x9c,0x12, - 0x29,0x9d,0x32,0x29,0xde,0x10,0x44,0xa9,0x14,0x4c,0xd9,0x94,0x8f,0x50,0x58,0x9a, - 0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0x57,0x9a,0x1b,0x5c,0x1d,0x1d,0xa5,0xb0, - 0x34,0x39,0x17,0xb6,0xb7,0xb1,0x30,0xba,0xb4,0x37,0xb7,0xaf,0x34,0x37,0xb2,0x32, - 0x3c,0x7a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64,0x28,0x5f,0x5f,0x61,0x69, - 0x72,0x5f,0x70,0x6c,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64,0x65,0x72,0x5f,0x5f,0x29, - 0x44,0xe0,0xde,0xe6,0xd2,0xe8,0xd2,0xde,0xdc,0x86,0x50,0x8b,0xa0,0x84,0x81,0x22, - 0x06,0x8b,0xb0,0x04,0xca,0x18,0x28,0x91,0x22,0x29,0x93,0x42,0x06,0x34,0xcc,0xd8, - 0xde,0xc2,0xe8,0x64,0x98,0xd0,0x95,0xe1,0x8d,0xbd,0xbd,0xc9,0x91,0xc1,0x0c,0xa1, - 0x96,0x40,0x09,0x03,0x45,0x0c,0x96,0x60,0x09,0x94,0x31,0x50,0x22,0xc5,0x0c,0x94, - 0x49,0x39,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x65,0x50,0xc2,0x40, - 0x11,0x83,0x65,0x58,0x02,0x65,0x0c,0x94,0x48,0x91,0x94,0x49,0x49,0x03,0x16,0x70, - 0x73,0x69,0x7a,0x65,0x43,0xa8,0xc5,0x50,0xc2,0x40,0x11,0x83,0xc5,0x58,0x02,0x65, - 0x0c,0x94,0x48,0xe9,0x94,0x49,0x59,0x03,0x2a,0x61,0x69,0x72,0x2e,0x62,0x75,0x66, - 0x66,0x65,0x72,0x7c,0xc2,0xd2,0xe4,0x5c,0xc4,0xea,0xcc,0xcc,0xca,0xe4,0xbe,0xe6, - 0xd2,0xf4,0xca,0x88,0x84,0xa5,0xc9,0xb9,0xc8,0x95,0x85,0x91,0x91,0x0a,0x4b,0x93, - 0x73,0x99,0xa3,0x93,0xab,0x1b,0xa3,0xfb,0xa2,0xcb,0x83,0x2b,0xfb,0x4a,0x73,0x33, - 0x7b,0x23,0x62,0xc6,0xf6,0x16,0x46,0x47,0x83,0x47,0xc3,0xa1,0xcd,0x0e,0x8e,0x02, - 0x5d,0xdb,0x10,0x6a,0x11,0x16,0x62,0x11,0x94,0x38,0x50,0xe4,0x60,0x21,0x16,0x62, - 0x11,0x94,0x38,0x50,0xe6,0x80,0x51,0x58,0x9a,0x9c,0x4b,0x98,0xdc,0xd9,0x17,0x5d, - 0x1e,0x5c,0xd9,0xd7,0x5c,0x9a,0x5e,0x19,0xaf,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3, - 0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x30,0xb6,0xb4,0x33,0xb7,0xaf,0xb9,0x34,0xbd,0x32, - 0x26,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x1c,0xbe,0x62,0x72,0x86,0x90, - 0xc1,0x52,0x28,0x6d,0xa0,0xb8,0xc1,0x72,0x28,0x62,0xb0,0x08,0x4b,0xa0,0xbc,0x81, - 0x02,0x07,0x0a,0x1d,0x28,0x75,0xb0,0x1c,0x8a,0x1d,0x2c,0x89,0x12,0x29,0x77,0xa0, - 0x4c,0x0a,0x1e,0x0c,0x51,0x94,0x32,0x50,0xd0,0x40,0x51,0x03,0x85,0x0d,0x94,0x3c, - 0x18,0x62,0x24,0x80,0x02,0x06,0x8a,0x1e,0xf0,0x79,0x6b,0x73,0x4b,0x83,0x7b,0xa3, - 0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3,0x33,0x95,0xd6,0x06,0xc7,0x56,0x06, - 0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34,0x44,0x50,0xfa,0x60,0x88,0xa1,0xf0, - 0x81,0xe2,0x07,0x8d,0x32,0xc4,0x50,0xfe,0x40,0xf9,0x83,0x46,0x19,0x11,0xb1,0x03, - 0x3b,0xd8,0x43,0x3b,0xb8,0x41,0x3b,0xbc,0x03,0x39,0xd4,0x03,0x3b,0x94,0x83,0x1b, - 0x98,0x03,0x3b,0x84,0xc3,0x39,0xcc,0xc3,0x14,0x21,0x18,0x46,0x28,0xec,0xc0,0x0e, - 0xf6,0xd0,0x0e,0x6e,0x90,0x0e,0xe4,0x50,0x0e,0xee,0x40,0x0f,0x53,0x82,0x62,0xc4, - 0x12,0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0, - 0x0e,0x53,0x02,0x63,0x04,0x15,0x0e,0xe9,0x20,0x0f,0x6e,0xc0,0x0e,0xe1,0xe0,0x0e, - 0xe7,0x50,0x0f,0xe1,0x70,0x0e,0xe5,0xf0,0x0b,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9, - 0xf0,0x0e,0xee,0x30,0x25,0x40,0x46,0x4c,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe3,0xf0, - 0x0e,0xed,0x00,0x0f,0xe9,0xc0,0x0e,0xe5,0xf0,0x0b,0xef,0x00,0x0f,0xf4,0x90,0x0e, - 0xef,0xe0,0x0e,0xf3,0x30,0x65,0x50,0x18,0x67,0x84,0x12,0x0e,0xe9,0x20,0x0f,0x6e, - 0x60,0x0f,0xe5,0x20,0x0f,0xf4,0x50,0x0e,0xf8,0x30,0x25,0xd8,0x03,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30, - 0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x3e,0x00,0x00,0x00,0x13,0x04,0x41, - 0x2c,0x10,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0xf4,0xc6,0x22,0x86,0x61,0x18,0xc6, - 0x22,0x04,0x41,0x10,0xc6,0x22,0x82,0x20,0x08,0xa8,0x95,0x40,0x19,0x14,0x01,0xbd, - 0x11,0x00,0x1a,0x33,0x00,0x24,0x66,0x00,0x28,0xcc,0x00,0x00,0x00,0xe3,0x15,0x4b, - 0x94,0x65,0x11,0x05,0x65,0x90,0x21,0x1a,0x0c,0x13,0x02,0xf9,0x8c,0x57,0x3c,0x55, - 0xd7,0x2d,0x14,0x94,0x41,0x86,0xea,0x70,0x4c,0x08,0xe4,0x63,0x41,0x01,0x9f,0xf1, - 0x0a,0x4a,0x13,0x03,0x31,0x70,0x28,0x28,0x83,0x0c,0x1a,0x43,0x99,0x10,0xc8,0xc7, - 0x8a,0x00,0x3e,0xe3,0x15,0xd9,0x77,0x06,0x67,0x40,0x51,0x50,0x06,0x19,0xbe,0x48, - 0x33,0x21,0x90,0x8f,0x15,0x01,0x7c,0xc6,0x2b,0x3c,0x32,0x68,0x03,0x36,0x20,0x03, - 0x0a,0xca,0x20,0xc3,0x18,0x60,0x99,0x09,0x81,0x7c,0xc6,0x2b,0xc4,0x00,0x0d,0xe2, - 0x00,0x0e,0x3c,0x0a,0xca,0x20,0xc3,0x19,0x70,0x61,0x60,0x42,0x20,0x1f,0x0b,0x0a, - 0xf8,0x8c,0x57,0x9c,0x41,0x1b,0xd8,0x41,0x1d,0x88,0x01,0x05,0xc5,0x86,0x00,0x3e, - 0xb3,0x0d,0x61,0x10,0x00,0xb3,0x0d,0x41,0x1b,0x04,0xb3,0x0d,0xc1,0x23,0xcc,0x36, - 0x04,0x6e,0x30,0x64,0x10,0x10,0x03,0x00,0x00,0x09,0x00,0x00,0x00,0x5b,0x86,0x20, - 0x00,0x85,0x2d,0x43,0x11,0x80,0xc2,0x96,0x41,0x09,0x40,0x61,0xcb,0xf0,0x04,0xa0, - 0xb0,0x65,0xa0,0x02,0x50,0xd8,0x32,0x60,0x01,0x28,0x6c,0x19,0xba,0x00,0x14,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sfons_fs_bytecode_metal_ios[2841] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x19,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x40,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0x7c,0x59,0x61,0x85,0x8c,0x08,0x62, - 0xf6,0xd0,0x45,0x0a,0x3a,0xcb,0xa8,0xa5,0x3c,0x2d,0x6c,0x6b,0x9c,0x3d,0xf0,0xf5, - 0xc4,0xdc,0xb5,0x90,0xdc,0xee,0x5a,0x9f,0x63,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x28,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x87,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1e,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x4c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x70,0x94,0x34,0x45,0x94,0x30, - 0xf9,0xff,0x44,0x5c,0x13,0x15,0x11,0xbf,0x3d,0xfc,0xd3,0x18,0x01,0x30,0x88,0x30, - 0x04,0x17,0x49,0x53,0x44,0x09,0x93,0xff,0x4b,0x00,0xf3,0x2c,0x44,0xf4,0x4f,0x63, - 0x04,0xc0,0x20,0x42,0x21,0x94,0x42,0x84,0x40,0x0c,0x9d,0x61,0x04,0x01,0x98,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0x88,0x49,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x30,0x02,0xb1,0x8c,0x00,0x00,0x00,0x00,0x00,0x13,0xa8,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51, - 0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78, - 0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0, - 0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90, - 0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06, - 0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72, - 0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10, - 0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73, - 0x20,0x07,0x43,0x18,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03, - 0x04,0x80,0x00,0x00,0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00, - 0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43, - 0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0x01,0x12,0x00, - 0x00,0x79,0x18,0x00,0x00,0xb7,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2, - 0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50, - 0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c, - 0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae, - 0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06, - 0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60, - 0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96, - 0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7, - 0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69, - 0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d, - 0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x21,0x19,0x84, - 0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95, - 0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85, - 0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59, - 0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9, - 0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61, - 0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8, - 0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e, - 0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08,0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e, - 0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99, - 0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37, - 0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74, - 0x69,0x76,0x65,0x14,0xea,0xec,0x86,0x48,0xcb,0xf0,0x58,0xcf,0xf5,0x60,0x4f,0xf6, - 0x40,0x4f,0xf4,0x48,0x8f,0xc6,0xa5,0x6e,0xae,0x4c,0x0e,0x85,0xed,0x6d,0xcc,0x2d, - 0x26,0x85,0xc5,0xd8,0x1b,0xdb,0x9b,0xdc,0x10,0x69,0x11,0x1e,0xeb,0xe1,0x1e,0xec, - 0xc9,0x1e,0xe8,0x89,0x1e,0xe9,0xe9,0xb8,0x84,0xa5,0xc9,0xb9,0xd0,0x95,0xe1,0xd1, - 0xd5,0xc9,0x95,0x51,0x0a,0x4b,0x93,0x73,0x61,0x7b,0x1b,0x0b,0xa3,0x4b,0x7b,0x73, - 0xfb,0x4a,0x73,0x23,0x2b,0xc3,0xa3,0x12,0x96,0x26,0xe7,0x32,0x17,0xd6,0x06,0xc7, - 0x56,0x46,0x8c,0xae,0x0c,0x8f,0xae,0x4e,0xae,0x4c,0x86,0x8c,0xc7,0x8c,0xed,0x2d, - 0x8c,0x8e,0x05,0x64,0x2e,0xac,0x0d,0x8e,0xad,0xcc,0x87,0x03,0x5d,0x19,0xde,0x10, - 0x6a,0x21,0x9e,0xef,0x01,0x83,0x65,0x58,0x84,0x27,0x0c,0x1e,0xe8,0x11,0x83,0x47, - 0x7a,0xc6,0x80,0x4b,0x58,0x9a,0x9c,0xcb,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x8f, - 0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39,0x0e,0x73,0x6d,0x70,0x43,0xa4,0xe5,0x78,0xca, - 0xe0,0x01,0x83,0x65,0x58,0x84,0x07,0x7a,0xcc,0xe0,0x91,0x9e,0x33,0x18,0x82,0x3c, - 0xdb,0xe3,0x3d,0x64,0xf0,0xa0,0xc1,0x10,0x03,0x01,0x9e,0xea,0x49,0x83,0x11,0x11, - 0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b,0xb4,0xc3,0x3b,0x90,0x43,0x3d,0xb0,0x43,0x39, - 0xb8,0x81,0x39,0xb0,0x43,0x38,0x9c,0xc3,0x3c,0x4c,0x11,0x82,0x61,0x84,0xc2,0x0e, - 0xec,0x60,0x0f,0xed,0xe0,0x06,0xe9,0x40,0x0e,0xe5,0xe0,0x0e,0xf4,0x30,0x25,0x28, - 0x46,0x2c,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9,0xf0, - 0x0e,0xee,0x30,0x25,0x30,0x46,0x50,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xec,0x10,0x0e, - 0xee,0x70,0x0e,0xf5,0x10,0x0e,0xe7,0x50,0x0e,0xbf,0x60,0x0f,0xe5,0x20,0x0f,0xf3, - 0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02,0x64,0xc4,0x14,0x0e,0xe9,0x20,0x0f,0x6e,0x30, - 0x0e,0xef,0xd0,0x0e,0xf0,0x90,0x0e,0xec,0x50,0x0e,0xbf,0xf0,0x0e,0xf0,0x40,0x0f, - 0xe9,0xf0,0x0e,0xee,0x30,0x0f,0x53,0x06,0x85,0x71,0x46,0x30,0xe1,0x90,0x0e,0xf2, - 0xe0,0x06,0xe6,0x20,0x0f,0xe1,0x70,0x0e,0xed,0x50,0x0e,0xee,0x40,0x0f,0x53,0x02, - 0x35,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80, - 0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80, - 0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80, - 0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88, - 0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78, - 0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03, - 0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f, - 0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c, - 0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39, - 0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60, - 0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87, - 0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e, - 0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c, - 0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6, - 0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94, - 0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03, - 0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07, - 0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f, - 0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33, - 0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc, - 0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c, - 0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78, - 0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca, - 0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21, - 0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43, - 0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87, - 0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c, - 0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e, - 0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c, - 0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c, - 0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00, - 0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45, - 0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00, - 0x00,0x61,0x20,0x00,0x00,0x16,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x14,0xc7,0x22,0x80,0x40,0x20,0x88,0x8d,0x00,0x8c,0x25, - 0x00,0x01,0xa9,0x11,0x80,0x1a,0x20,0x31,0x03,0x40,0x61,0x0e,0xe2,0xba,0xae,0x6a, - 0x06,0x80,0xc0,0x0c,0xc0,0x08,0xc0,0x18,0x01,0x08,0x82,0x20,0xfe,0x01,0x00,0x00, - 0x00,0x83,0x0c,0x0f,0x91,0x8c,0x18,0x28,0x42,0x80,0x39,0x4d,0x80,0x2c,0xc9,0x30, - 0xc8,0x70,0x04,0x8d,0x05,0x91,0x7c,0x66,0x1b,0x94,0x00,0xc8,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sfons_vs_source_metal_sim[756] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x6d,0x76,0x70,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x74,0x6d,0x3b,0x0a,0x7d,0x3b, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, - 0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, - 0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a, - 0x65,0x20,0x5b,0x5b,0x70,0x6f,0x69,0x6e,0x74,0x5f,0x73,0x69,0x7a,0x65,0x5d,0x5d, - 0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, - 0x74,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74, - 0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72, - 0x64,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31, - 0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75, - 0x74,0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x20,0x70,0x73,0x69,0x7a,0x65,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69, - 0x62,0x75,0x74,0x65,0x28,0x33,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76, - 0x65,0x72,0x74,0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20, - 0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69, - 0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20, - 0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x26,0x20,0x5f,0x31,0x39,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72, - 0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70,0x20,0x2a, - 0x20,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69, - 0x7a,0x65,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20, - 0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75,0x76,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e, - 0x74,0x6d,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31, - 0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sfons_fs_source_metal_sim[464] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65, - 0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65, - 0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d, - 0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b, - 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, - 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, - 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x34,0x28,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e, - 0x30,0x2c,0x20,0x74,0x65,0x78,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d, - 0x70,0x2c,0x20,0x69,0x6e,0x2e,0x75,0x76,0x2e,0x78,0x79,0x29,0x2e,0x78,0x29,0x20, - 0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, - -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _sfons_vs_bytecode_hlsl4[1032] = { - 0x44,0x58,0x42,0x43,0x74,0x7f,0x01,0xd9,0xf4,0xd5,0xed,0x1d,0x74,0xc1,0x30,0x27, - 0xd8,0xe9,0x9d,0x50,0x01,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x90,0x01,0x00,0x00,0x00,0x02,0x00,0x00, - 0x8c,0x03,0x00,0x00,0x52,0x44,0x45,0x46,0xd8,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0xaf,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x60,0x00,0x00,0x00, - 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x98,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f, - 0x6d,0x76,0x70,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f,0x74,0x6d,0x00,0x4d,0x69,0x63,0x72,0x6f, - 0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68, - 0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30, - 0x2e,0x31,0x00,0xab,0x49,0x53,0x47,0x4e,0x74,0x00,0x00,0x00,0x04,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x68,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x68,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x68,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab, - 0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab, - 0x53,0x48,0x44,0x52,0x84,0x01,0x00,0x00,0x40,0x00,0x01,0x00,0x61,0x00,0x00,0x00, - 0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, - 0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00, - 0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04, - 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02, - 0x01,0x00,0x00,0x00,0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x56,0x15,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x06,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x04,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x36,0x00,0x00,0x05, - 0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00, - 0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x56,0x15,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0xa6,0x1a,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x32,0x00,0x00,0x0a,0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0xf6,0x1f,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54, - 0x74,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sfons_fs_bytecode_hlsl4[628] = { - 0x44,0x58,0x42,0x43,0xb6,0x66,0xf0,0xfc,0x09,0x54,0x2a,0x35,0x84,0x1d,0x27,0xd2, - 0xff,0xb3,0x2e,0xdb,0x01,0x00,0x00,0x00,0x74,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x48,0x01,0x00,0x00, - 0xf8,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0x64,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c, - 0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x03,0x00,0x00, - 0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54, - 0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0xa8,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00, - 0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00, - 0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x96,0x73,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0x12,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x01,0x40,0x00,0x00,0x00,0x00,0x80,0x3f,0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00, - 0x00,0x00,0x00,0x00,0x06,0x0c,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00, - 0x01,0x00,0x00,0x00,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00, - 0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, -}; -#elif defined(SOKOL_WGPU) -static const uint8_t _sfons_vs_source_wgsl[1162] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x6d,0x76,0x70,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78,0x34,0x66,0x2c,0x0a, - 0x20,0x20,0x2f,0x2a,0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x36,0x34,0x29, - 0x20,0x2a,0x2f,0x0a,0x20,0x20,0x74,0x6d,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78, - 0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x30,0x29, - 0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20,0x76,0x61,0x72, - 0x3c,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x31,0x39,0x20,0x3a, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x76,0x61,0x72, - 0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76, - 0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72, - 0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x70,0x73,0x69,0x7a,0x65,0x20,0x3a,0x20,0x66,0x33,0x32,0x3b,0x0a,0x0a, - 0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b, - 0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x32,0x20,0x3a,0x20,0x6d,0x61, - 0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x35,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f, - 0x31,0x3b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x32,0x20,0x2a,0x20,0x78,0x5f,0x32,0x35,0x29, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x32,0x20,0x3a,0x20,0x6d, - 0x61,0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x74,0x6d, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x36,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30, - 0x3b,0x0a,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x28,0x78,0x5f,0x33,0x32,0x20,0x2a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x33,0x36,0x2e,0x78,0x2c,0x20,0x78, - 0x5f,0x33,0x36,0x2e,0x79,0x2c,0x20,0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30, - 0x66,0x29,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x35,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x78,0x5f,0x34,0x35, - 0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73, - 0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b, - 0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c,0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x0a,0x20,0x20,0x75,0x76, - 0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a, - 0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x32,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c, - 0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x33,0x29,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x66,0x33,0x32,0x29, - 0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20, - 0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x3d,0x20,0x74,0x65, - 0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x70,0x73,0x69,0x7a,0x65,0x20, - 0x3d,0x20,0x70,0x73,0x69,0x7a,0x65,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74, - 0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sfons_fs_source_wgsl[674] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x34,0x38, - 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, - 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x36,0x34,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x36,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x78,0x5f,0x32,0x34,0x2e,0x78, - 0x2c,0x20,0x78,0x5f,0x32,0x34,0x2e,0x79,0x29,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x33,0x32,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x28,0x76,0x65,0x63,0x34,0x66,0x28,0x31,0x2e, - 0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x2c,0x20, - 0x78,0x5f,0x32,0x36,0x2e,0x78,0x29,0x20,0x2a,0x20,0x78,0x5f,0x33,0x32,0x29,0x3b, - 0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74, - 0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a, - 0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x0a,0x20, - 0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x66,0x72,0x61,0x67,0x6d, - 0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63, - 0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20, - 0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x75,0x76,0x20, - 0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20, - 0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74, - 0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a, - 0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _sfons_vs_source_dummy = ""; -static const char* _sfons_fs_source_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -typedef struct _sfons_t { - sfons_desc_t desc; - sg_shader shd; - sgl_pipeline pip; - sg_image img; - sg_sampler smp; - int cur_width, cur_height; - bool img_dirty; -} _sfons_t; - -static void _sfons_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -static void* _sfons_malloc(const sfons_allocator_t* allocator, size_t size) { - SOKOL_ASSERT(allocator && (size > 0)); - void* ptr; - if (allocator->alloc_fn) { - ptr = allocator->alloc_fn(size, allocator->user_data); - } else { - ptr = malloc(size); - } - SOKOL_ASSERT(ptr); - return ptr; -} - -static void* _sfons_malloc_clear(const sfons_allocator_t* allocator, size_t size) { - void* ptr = _sfons_malloc(allocator, size); - _sfons_clear(ptr, size); - return ptr; -} - -static void _sfons_free(const sfons_allocator_t* allocator, void* ptr) { - SOKOL_ASSERT(allocator); - if (allocator->free_fn) { - allocator->free_fn(ptr, allocator->user_data); - } else { - free(ptr); - } -} - -static int _sfons_render_create(void* user_ptr, int width, int height) { - SOKOL_ASSERT(user_ptr && (width > 8) && (height > 8)); - _sfons_t* sfons = (_sfons_t*) user_ptr; - - // sokol-gl compatible shader which treats RED channel as alpha - if (sfons->shd.id == SG_INVALID_ID) { - sg_shader_desc shd_desc; - _sfons_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[3].name = "psize"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - shd_desc.attrs[3].sem_name = "TEXCOORD"; - shd_desc.attrs[3].sem_index = 3; - sg_shader_uniform_block_desc* ub = &shd_desc.vs.uniform_blocks[0]; - ub->size = 128; - ub->uniforms[0].name = "vs_params"; - ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - ub->uniforms[0].array_count = 8; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.label = "sokol-fontstash-shader"; - #if defined(SOKOL_GLCORE) - shd_desc.vs.source = (const char*)_sfons_vs_source_glsl410; - shd_desc.fs.source = (const char*)_sfons_fs_source_glsl410; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = (const char*)_sfons_vs_source_glsl300es; - shd_desc.fs.source = (const char*)_sfons_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = (const char*)_sfons_vs_source_metal_sim; - shd_desc.fs.source = (const char*)_sfons_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = (const char*)_sfons_vs_source_wgsl; - shd_desc.fs.source = (const char*)_sfons_fs_source_wgsl; - #else - shd_desc.vs.source = _sfons_vs_source_dummy; - shd_desc.fs.source = _sfons_fs_source_dummy; - #endif - shd_desc.label = "sfons-shader"; - sfons->shd = sg_make_shader(&shd_desc); - } - - // sokol-gl pipeline object - if (sfons->pip.id == SG_INVALID_ID) { - sg_pipeline_desc pip_desc; - _sfons_clear(&pip_desc, sizeof(pip_desc)); - pip_desc.shader = sfons->shd; - pip_desc.colors[0].blend.enabled = true; - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - sfons->pip = sgl_make_pipeline(&pip_desc); - } - - // a sampler object - if (sfons->smp.id == SG_INVALID_ID) { - sg_sampler_desc smp_desc; - _sfons_clear(&smp_desc, sizeof(smp_desc)); - smp_desc.min_filter = SG_FILTER_LINEAR; - smp_desc.mag_filter = SG_FILTER_LINEAR; - sfons->smp = sg_make_sampler(&smp_desc); - } - - // create or re-create font atlas texture - if (sfons->img.id != SG_INVALID_ID) { - sg_destroy_image(sfons->img); - sfons->img.id = SG_INVALID_ID; - } - sfons->cur_width = width; - sfons->cur_height = height; - - SOKOL_ASSERT(sfons->img.id == SG_INVALID_ID); - sg_image_desc img_desc; - _sfons_clear(&img_desc, sizeof(img_desc)); - img_desc.width = sfons->cur_width; - img_desc.height = sfons->cur_height; - img_desc.usage = SG_USAGE_DYNAMIC; - img_desc.pixel_format = SG_PIXELFORMAT_R8; - sfons->img = sg_make_image(&img_desc); - return 1; -} - -static int _sfons_render_resize(void* user_ptr, int width, int height) { - return _sfons_render_create(user_ptr, width, height); -} - -static void _sfons_render_update(void* user_ptr, int* rect, const unsigned char* data) { - SOKOL_ASSERT(user_ptr && rect && data); - _SOKOL_UNUSED(rect); - _SOKOL_UNUSED(data); - _sfons_t* sfons = (_sfons_t*) user_ptr; - sfons->img_dirty = true; -} - -static void _sfons_render_draw(void* user_ptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts) { - SOKOL_ASSERT(user_ptr && verts && tcoords && colors && (nverts > 0)); - _sfons_t* sfons = (_sfons_t*) user_ptr; - sgl_enable_texture(); - sgl_texture(sfons->img, sfons->smp); - sgl_push_pipeline(); - sgl_load_pipeline(sfons->pip); - sgl_begin_triangles(); - for (int i = 0; i < nverts; i++) { - sgl_v2f_t2f_c1i(verts[2*i+0], verts[2*i+1], tcoords[2*i+0], tcoords[2*i+1], colors[i]); - } - sgl_end(); - sgl_pop_pipeline(); - sgl_disable_texture(); -} - -static void _sfons_render_delete(void* user_ptr) { - SOKOL_ASSERT(user_ptr); - _sfons_t* sfons = (_sfons_t*) user_ptr; - if (sfons->img.id != SG_INVALID_ID) { - sg_destroy_image(sfons->img); - sfons->img.id = SG_INVALID_ID; - } - if (sfons->smp.id != SG_INVALID_ID) { - sg_destroy_sampler(sfons->smp); - sfons->smp.id = SG_INVALID_ID; - } - if (sfons->pip.id != SG_INVALID_ID) { - sgl_destroy_pipeline(sfons->pip); - sfons->pip.id = SG_INVALID_ID; - } - if (sfons->shd.id != SG_INVALID_ID) { - sg_destroy_shader(sfons->shd); - sfons->shd.id = SG_INVALID_ID; - } -} - -#define _sfons_def(val, def) (((val) == 0) ? (def) : (val)) - -static sfons_desc_t _sfons_desc_defaults(const sfons_desc_t* desc) { - SOKOL_ASSERT(desc); - sfons_desc_t res = *desc; - res.width = _sfons_def(res.width, 512); - res.height = _sfons_def(res.height, 512); - return res; -} - -SOKOL_API_IMPL FONScontext* sfons_create(const sfons_desc_t* desc) { - SOKOL_ASSERT(desc); - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - _sfons_t* sfons = (_sfons_t*) _sfons_malloc_clear(&desc->allocator, sizeof(_sfons_t)); - sfons->desc = _sfons_desc_defaults(desc); - FONSparams params; - _sfons_clear(¶ms, sizeof(params)); - params.width = sfons->desc.width; - params.height = sfons->desc.height; - params.flags = FONS_ZERO_TOPLEFT; - params.renderCreate = _sfons_render_create; - params.renderResize = _sfons_render_resize; - params.renderUpdate = _sfons_render_update; - params.renderDraw = _sfons_render_draw; - params.renderDelete = _sfons_render_delete; - params.userPtr = sfons; - return fonsCreateInternal(¶ms); -} - -SOKOL_API_IMPL void sfons_destroy(FONScontext* ctx) { - SOKOL_ASSERT(ctx); - _sfons_t* sfons = (_sfons_t*) ctx->params.userPtr; - fonsDeleteInternal(ctx); - const sfons_allocator_t allocator = sfons->desc.allocator; - _sfons_free(&allocator, sfons); -} - -SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) { - SOKOL_ASSERT(ctx && ctx->params.userPtr); - _sfons_t* sfons = (_sfons_t*) ctx->params.userPtr; - if (sfons->img_dirty) { - sfons->img_dirty = false; - sg_image_data data; - _sfons_clear(&data, sizeof(data)); - data.subimage[0][0].ptr = ctx->texData; - data.subimage[0][0].size = (size_t) (sfons->cur_width * sfons->cur_height); - sg_update_image(sfons->img, &data); - } -} - -SOKOL_API_IMPL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return ((uint32_t)r) | ((uint32_t)g<<8) | ((uint32_t)b<<16) | ((uint32_t)a<<24); -} - -#endif // SOKOL_FONTSTASH_IMPL diff --git a/source/thirdparty/sokol/util/sokol_gfx_imgui.h b/source/thirdparty/sokol/util/sokol_gfx_imgui.h deleted file mode 100644 index 5aea7ec1..00000000 --- a/source/thirdparty/sokol/util/sokol_gfx_imgui.h +++ /dev/null @@ -1,4765 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_GFX_IMGUI_IMPL) -#define SOKOL_GFX_IMGUI_IMPL -#endif -#ifndef SOKOL_GFX_IMGUI_INCLUDED -/* - sokol_gfx_imgui.h -- debug-inspection UI for sokol_gfx.h using Dear ImGui - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_GFX_IMGUI_IMPL - - before you include this file in *one* C or C++ file to create the - implementation. - - NOTE that the implementation can be compiled either as C++ or as C. - When compiled as C++, sokol_gfx_imgui.h will directly call into the - Dear ImGui C++ API. When compiled as C, sokol_gfx_imgui.h will call - cimgui.h functions instead. - - Include the following file(s) before including sokol_gfx_imgui.h: - - sokol_gfx.h - - Additionally, include the following headers before including the - implementation: - - If the implementation is compiled as C++: - imgui.h - - If the implementation is compiled as C: - cimgui.h - - The sokol_gfx.h implementation must be compiled with debug trace hooks - enabled by defining: - - SOKOL_TRACE_HOOKS - - ...before including the sokol_gfx.h implementation. - - Before including the sokol_gfx_imgui.h implementation, optionally - override the following macros: - - SOKOL_ASSERT(c) -- your own assert macro, default: assert(c) - SOKOL_UNREACHABLE -- your own macro to annotate unreachable code, - default: SOKOL_ASSERT(false) - SOKOL_GFX_IMGUI_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_GFX_IMGUI_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_gfx_imgui.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_GFX_IMGUI_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - STEP BY STEP: - ============= - --- create an sgimgui_t struct (which must be preserved between frames) - and initialize it with: - - sgimgui_init(&sgimgui, &(sgimgui_desc_t){ 0 }); - - Note that from C++ you can't inline the desc structure initialization: - - const sgimgui_desc_t desc = { }; - sgimgui_init(&sgimgui, &desc); - - Provide optional memory allocator override functions (compatible with malloc/free) like this: - - sgimgui_init(&sgimgui, &(sgimgui_desc_t){ - .allocator = { - .alloc_fn = my_malloc, - .free_fn = my_free, - } - }); - - --- somewhere in the per-frame code call: - - sgimgui_draw(&sgimgui) - - this won't draw anything yet, since no windows are open. - - --- call the convenience function sgimgui_draw_menu(ctx, title) - to render a menu which allows to open/close the provided debug windows - - sgimgui_draw_menu(&sgimgui, "sokol-gfx"); - - --- alternative, open and close windows directly by setting the following public - booleans in the sgimgui_t struct: - - sgimgui.caps_window.open = true; - sgimgui.frame_stats_window.open = true; - sgimgui.buffer_window.open = true; - sgimgui.image_window.open = true; - sgimgui.sampler_window.open = true; - sgimgui.shader_window.open = true; - sgimgui.pipeline_window.open = true; - sgimgui.attachments_window.open = true; - sgimgui.capture_window.open = true; - sgimgui.frame_stats_window.open = true; - - ...for instance, to control the window visibility through - menu items, the following code can be used: - - if (ImGui::BeginMainMenuBar()) { - if (ImGui::BeginMenu("sokol-gfx")) { - ImGui::MenuItem("Capabilities", 0, &sgimgui.caps_window.open); - ImGui::MenuItem("Frame Stats", 0, &sgimgui.frame_stats_window.open); - ImGui::MenuItem("Buffers", 0, &sgimgui.buffer_window.open); - ImGui::MenuItem("Images", 0, &sgimgui.image_window.open); - ImGui::MenuItem("Samplers", 0, &sgimgui.sampler_window.open); - ImGui::MenuItem("Shaders", 0, &sgimgui.shader_window.open); - ImGui::MenuItem("Pipelines", 0, &sgimgui.pipeline_window.open); - ImGui::MenuItem("Attachments", 0, &sgimgui.attachments_window.open); - ImGui::MenuItem("Calls", 0, &sgimgui.capture_window.open); - ImGui::EndMenu(); - } - ImGui::EndMainMenuBar(); - } - - --- before application shutdown, call: - - sgimgui_discard(&sgimgui); - - ...this is not strictly necessary because the application exits - anyway, but not doing this may trigger memory leak detection tools. - - --- finally, your application needs an ImGui renderer, you can either - provide your own, or drop in the sokol_imgui.h utility header - - ALTERNATIVE DRAWING FUNCTIONS: - ============================== - Instead of the convenient, but all-in-one sgimgui_draw() function, - you can also use the following granular functions which might allow - better integration with your existing UI: - - The following functions only render the window *content* (so you - can integrate the UI into you own windows): - - void sgimgui_draw_buffer_window_content(sgimgui_t* ctx); - void sgimgui_draw_image_window_content(sgimgui_t* ctx); - void sgimgui_draw_sampler_window_content(sgimgui_t* ctx); - void sgimgui_draw_shader_window_content(sgimgui_t* ctx); - void sgimgui_draw_pipeline_window_content(sgimgui_t* ctx); - void sgimgui_draw_attachments_window_content(sgimgui_t* ctx); - void sgimgui_draw_capture_window_content(sgimgui_t* ctx); - - And these are the 'full window' drawing functions: - - void sgimgui_draw_buffer_window(sgimgui_t* ctx); - void sgimgui_draw_image_window(sgimgui_t* ctx); - void sgimgui_draw_sampler_window(sgimgui_t* ctx); - void sgimgui_draw_shader_window(sgimgui_t* ctx); - void sgimgui_draw_pipeline_window(sgimgui_t* ctx); - void sgimgui_draw_attachments_window(sgimgui_t* ctx); - void sgimgui_draw_capture_window(sgimgui_t* ctx); - - Finer-grained drawing functions may be moved to the public API - in the future as needed. - - 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); - } - - ... - sgimgui_init(&(&ctx, &(sgimgui_desc_t){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ...; - } - }); - ... - - This only affects memory allocation calls done by sokol_gfx_imgui.h - itself though, not any allocations in OS libraries. - - - 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. -*/ -#define SOKOL_GFX_IMGUI_INCLUDED (1) -#include -#include -#include // size_t - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_gfx_imgui.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_GFX_IMGUI_API_DECL) -#define SOKOL_GFX_IMGUI_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_GFX_IMGUI_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GFX_IMGUI_IMPL) -#define SOKOL_GFX_IMGUI_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_GFX_IMGUI_API_DECL __declspec(dllimport) -#else -#define SOKOL_GFX_IMGUI_API_DECL extern -#endif -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -#define sgimgui_STRBUF_LEN (96) -/* max number of captured calls per frame */ -#define sgimgui_MAX_FRAMECAPTURE_ITEMS (4096) - -typedef struct sgimgui_str_t { - char buf[sgimgui_STRBUF_LEN]; -} sgimgui_str_t; - -typedef struct sgimgui_buffer_t { - sg_buffer res_id; - sgimgui_str_t label; - sg_buffer_desc desc; -} sgimgui_buffer_t; - -typedef struct sgimgui_image_t { - sg_image res_id; - float ui_scale; - sgimgui_str_t label; - sg_image_desc desc; - simgui_image_t simgui_img; -} sgimgui_image_t; - -typedef struct sgimgui_sampler_t { - sg_sampler res_id; - sgimgui_str_t label; - sg_sampler_desc desc; -} sgimgui_sampler_t; - -typedef struct sgimgui_shader_t { - sg_shader res_id; - sgimgui_str_t label; - sgimgui_str_t vs_entry; - sgimgui_str_t vs_d3d11_target; - sgimgui_str_t vs_image_sampler_name[SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]; - sgimgui_str_t vs_uniform_name[SG_MAX_SHADERSTAGE_UBS][SG_MAX_UB_MEMBERS]; - sgimgui_str_t fs_entry; - sgimgui_str_t fs_d3d11_target; - sgimgui_str_t fs_image_sampler_name[SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]; - sgimgui_str_t fs_uniform_name[SG_MAX_SHADERSTAGE_UBS][SG_MAX_UB_MEMBERS]; - sgimgui_str_t attr_name[SG_MAX_VERTEX_ATTRIBUTES]; - sgimgui_str_t attr_sem_name[SG_MAX_VERTEX_ATTRIBUTES]; - sg_shader_desc desc; -} sgimgui_shader_t; - -typedef struct sgimgui_pipeline_t { - sg_pipeline res_id; - sgimgui_str_t label; - sg_pipeline_desc desc; -} sgimgui_pipeline_t; - -typedef struct sgimgui_attachments_t { - sg_attachments res_id; - sgimgui_str_t label; - float color_image_scale[SG_MAX_COLOR_ATTACHMENTS]; - float resolve_image_scale[SG_MAX_COLOR_ATTACHMENTS]; - float ds_image_scale; - sg_attachments_desc desc; -} sgimgui_attachments_t; - -typedef struct sgimgui_buffer_window_t { - bool open; - int num_slots; - sg_buffer sel_buf; - sgimgui_buffer_t* slots; -} sgimgui_buffer_window_t; - -typedef struct sgimgui_image_window_t { - bool open; - int num_slots; - sg_image sel_img; - sgimgui_image_t* slots; -} sgimgui_image_window_t; - -typedef struct sgimgui_sampler_window_t { - bool open; - int num_slots; - sg_sampler sel_smp; - sgimgui_sampler_t* slots; -} sgimgui_sampler_window_t; - -typedef struct sgimgui_shader_window_t { - bool open; - int num_slots; - sg_shader sel_shd; - sgimgui_shader_t* slots; -} sgimgui_shader_window_t; - -typedef struct sgimgui_pipeline_window_t { - bool open; - int num_slots; - sg_pipeline sel_pip; - sgimgui_pipeline_t* slots; -} sgimgui_pipeline_window_t; - -typedef struct sgimgui_attachments_window_t { - bool open; - int num_slots; - sg_attachments sel_atts; - sgimgui_attachments_t* slots; -} sgimgui_attachments_window_t; - -typedef enum sgimgui_cmd_t { - SGIMGUI_CMD_INVALID, - SGIMGUI_CMD_RESET_STATE_CACHE, - SGIMGUI_CMD_MAKE_BUFFER, - SGIMGUI_CMD_MAKE_IMAGE, - SGIMGUI_CMD_MAKE_SAMPLER, - SGIMGUI_CMD_MAKE_SHADER, - SGIMGUI_CMD_MAKE_PIPELINE, - SGIMGUI_CMD_MAKE_ATTACHMENTS, - SGIMGUI_CMD_DESTROY_BUFFER, - SGIMGUI_CMD_DESTROY_IMAGE, - SGIMGUI_CMD_DESTROY_SAMPLER, - SGIMGUI_CMD_DESTROY_SHADER, - SGIMGUI_CMD_DESTROY_PIPELINE, - SGIMGUI_CMD_DESTROY_ATTACHMENTS, - SGIMGUI_CMD_UPDATE_BUFFER, - SGIMGUI_CMD_UPDATE_IMAGE, - SGIMGUI_CMD_APPEND_BUFFER, - SGIMGUI_CMD_BEGIN_PASS, - SGIMGUI_CMD_APPLY_VIEWPORT, - SGIMGUI_CMD_APPLY_SCISSOR_RECT, - SGIMGUI_CMD_APPLY_PIPELINE, - SGIMGUI_CMD_APPLY_BINDINGS, - SGIMGUI_CMD_APPLY_UNIFORMS, - SGIMGUI_CMD_DRAW, - SGIMGUI_CMD_END_PASS, - SGIMGUI_CMD_COMMIT, - SGIMGUI_CMD_ALLOC_BUFFER, - SGIMGUI_CMD_ALLOC_IMAGE, - SGIMGUI_CMD_ALLOC_SAMPLER, - SGIMGUI_CMD_ALLOC_SHADER, - SGIMGUI_CMD_ALLOC_PIPELINE, - SGIMGUI_CMD_ALLOC_ATTACHMENTS, - SGIMGUI_CMD_DEALLOC_BUFFER, - SGIMGUI_CMD_DEALLOC_IMAGE, - SGIMGUI_CMD_DEALLOC_SAMPLER, - SGIMGUI_CMD_DEALLOC_SHADER, - SGIMGUI_CMD_DEALLOC_PIPELINE, - SGIMGUI_CMD_DEALLOC_ATTACHMENTS, - SGIMGUI_CMD_INIT_BUFFER, - SGIMGUI_CMD_INIT_IMAGE, - SGIMGUI_CMD_INIT_SAMPLER, - SGIMGUI_CMD_INIT_SHADER, - SGIMGUI_CMD_INIT_PIPELINE, - SGIMGUI_CMD_INIT_ATTACHMENTS, - SGIMGUI_CMD_UNINIT_BUFFER, - SGIMGUI_CMD_UNINIT_IMAGE, - SGIMGUI_CMD_UNINIT_SAMPLER, - SGIMGUI_CMD_UNINIT_SHADER, - SGIMGUI_CMD_UNINIT_PIPELINE, - SGIMGUI_CMD_UNINIT_ATTACHMENTS, - SGIMGUI_CMD_FAIL_BUFFER, - SGIMGUI_CMD_FAIL_IMAGE, - SGIMGUI_CMD_FAIL_SAMPLER, - SGIMGUI_CMD_FAIL_SHADER, - SGIMGUI_CMD_FAIL_PIPELINE, - SGIMGUI_CMD_FAIL_ATTACHMENTS, - SGIMGUI_CMD_PUSH_DEBUG_GROUP, - SGIMGUI_CMD_POP_DEBUG_GROUP, -} sgimgui_cmd_t; - -typedef struct sgimgui_args_make_buffer_t { - sg_buffer result; -} sgimgui_args_make_buffer_t; - -typedef struct sgimgui_args_make_image_t { - sg_image result; -} sgimgui_args_make_image_t; - -typedef struct sgimgui_args_make_sampler_t { - sg_sampler result; -} sgimgui_args_make_sampler_t; - -typedef struct sgimgui_args_make_shader_t { - sg_shader result; -} sgimgui_args_make_shader_t; - -typedef struct sgimgui_args_make_pipeline_t { - sg_pipeline result; -} sgimgui_args_make_pipeline_t; - -typedef struct sgimgui_args_make_attachments_t { - sg_attachments result; -} sgimgui_args_make_attachments_t; - -typedef struct sgimgui_args_destroy_buffer_t { - sg_buffer buffer; -} sgimgui_args_destroy_buffer_t; - -typedef struct sgimgui_args_destroy_image_t { - sg_image image; -} sgimgui_args_destroy_image_t; - -typedef struct sgimgui_args_destroy_sampler_t { - sg_sampler sampler; -} sgimgui_args_destroy_sampler_t; - -typedef struct sgimgui_args_destroy_shader_t { - sg_shader shader; -} sgimgui_args_destroy_shader_t; - -typedef struct sgimgui_args_destroy_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_destroy_pipeline_t; - -typedef struct sgimgui_args_destroy_attachments_t { - sg_attachments attachments; -} sgimgui_args_destroy_attachments_t; - -typedef struct sgimgui_args_update_buffer_t { - sg_buffer buffer; - size_t data_size; -} sgimgui_args_update_buffer_t; - -typedef struct sgimgui_args_update_image_t { - sg_image image; -} sgimgui_args_update_image_t; - -typedef struct sgimgui_args_append_buffer_t { - sg_buffer buffer; - size_t data_size; - int result; -} sgimgui_args_append_buffer_t; - -typedef struct sgimgui_args_begin_pass_t { - sg_pass pass; -} sgimgui_args_begin_pass_t; - -typedef struct sgimgui_args_apply_viewport_t { - int x, y, width, height; - bool origin_top_left; -} sgimgui_args_apply_viewport_t; - -typedef struct sgimgui_args_apply_scissor_rect_t { - int x, y, width, height; - bool origin_top_left; -} sgimgui_args_apply_scissor_rect_t; - -typedef struct sgimgui_args_apply_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_apply_pipeline_t; - -typedef struct sgimgui_args_apply_bindings_t { - sg_bindings bindings; -} sgimgui_args_apply_bindings_t; - -typedef struct sgimgui_args_apply_uniforms_t { - sg_shader_stage stage; - int ub_index; - size_t data_size; - sg_pipeline pipeline; /* the pipeline which was active at this call */ - size_t ubuf_pos; /* start of copied data in capture buffer */ -} sgimgui_args_apply_uniforms_t; - -typedef struct sgimgui_args_draw_t { - int base_element; - int num_elements; - int num_instances; -} sgimgui_args_draw_t; - -typedef struct sgimgui_args_alloc_buffer_t { - sg_buffer result; -} sgimgui_args_alloc_buffer_t; - -typedef struct sgimgui_args_alloc_image_t { - sg_image result; -} sgimgui_args_alloc_image_t; - -typedef struct sgimgui_args_alloc_sampler_t { - sg_sampler result; -} sgimgui_args_alloc_sampler_t; - -typedef struct sgimgui_args_alloc_shader_t { - sg_shader result; -} sgimgui_args_alloc_shader_t; - -typedef struct sgimgui_args_alloc_pipeline_t { - sg_pipeline result; -} sgimgui_args_alloc_pipeline_t; - -typedef struct sgimgui_args_alloc_attachments_t { - sg_attachments result; -} sgimgui_args_alloc_attachments_t; - -typedef struct sgimgui_args_dealloc_buffer_t { - sg_buffer buffer; -} sgimgui_args_dealloc_buffer_t; - -typedef struct sgimgui_args_dealloc_image_t { - sg_image image; -} sgimgui_args_dealloc_image_t; - -typedef struct sgimgui_args_dealloc_sampler_t { - sg_sampler sampler; -} sgimgui_args_dealloc_sampler_t; - -typedef struct sgimgui_args_dealloc_shader_t { - sg_shader shader; -} sgimgui_args_dealloc_shader_t; - -typedef struct sgimgui_args_dealloc_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_dealloc_pipeline_t; - -typedef struct sgimgui_args_dealloc_attachments_t { - sg_attachments attachments; -} sgimgui_args_dealloc_attachments_t; - -typedef struct sgimgui_args_init_buffer_t { - sg_buffer buffer; -} sgimgui_args_init_buffer_t; - -typedef struct sgimgui_args_init_image_t { - sg_image image; -} sgimgui_args_init_image_t; - -typedef struct sgimgui_args_init_sampler_t { - sg_sampler sampler; -} sgimgui_args_init_sampler_t; - -typedef struct sgimgui_args_init_shader_t { - sg_shader shader; -} sgimgui_args_init_shader_t; - -typedef struct sgimgui_args_init_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_init_pipeline_t; - -typedef struct sgimgui_args_init_attachments_t { - sg_attachments attachments; -} sgimgui_args_init_attachments_t; - -typedef struct sgimgui_args_uninit_buffer_t { - sg_buffer buffer; -} sgimgui_args_uninit_buffer_t; - -typedef struct sgimgui_args_uninit_image_t { - sg_image image; -} sgimgui_args_uninit_image_t; - -typedef struct sgimgui_args_uninit_sampler_t { - sg_sampler sampler; -} sgimgui_args_uninit_sampler_t; - -typedef struct sgimgui_args_uninit_shader_t { - sg_shader shader; -} sgimgui_args_uninit_shader_t; - -typedef struct sgimgui_args_uninit_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_uninit_pipeline_t; - -typedef struct sgimgui_args_uninit_attachments_t { - sg_attachments attachments; -} sgimgui_args_uninit_attachments_t; - -typedef struct sgimgui_args_fail_buffer_t { - sg_buffer buffer; -} sgimgui_args_fail_buffer_t; - -typedef struct sgimgui_args_fail_image_t { - sg_image image; -} sgimgui_args_fail_image_t; - -typedef struct sgimgui_args_fail_sampler_t { - sg_sampler sampler; -} sgimgui_args_fail_sampler_t; - -typedef struct sgimgui_args_fail_shader_t { - sg_shader shader; -} sgimgui_args_fail_shader_t; - -typedef struct sgimgui_args_fail_pipeline_t { - sg_pipeline pipeline; -} sgimgui_args_fail_pipeline_t; - -typedef struct sgimgui_args_fail_attachments_t { - sg_attachments attachments; -} sgimgui_args_fail_attachments_t; - -typedef struct sgimgui_args_push_debug_group_t { - sgimgui_str_t name; -} sgimgui_args_push_debug_group_t; - -typedef union sgimgui_args_t { - sgimgui_args_make_buffer_t make_buffer; - sgimgui_args_make_image_t make_image; - sgimgui_args_make_sampler_t make_sampler; - sgimgui_args_make_shader_t make_shader; - sgimgui_args_make_pipeline_t make_pipeline; - sgimgui_args_make_attachments_t make_attachments; - sgimgui_args_destroy_buffer_t destroy_buffer; - sgimgui_args_destroy_image_t destroy_image; - sgimgui_args_destroy_sampler_t destroy_sampler; - sgimgui_args_destroy_shader_t destroy_shader; - sgimgui_args_destroy_pipeline_t destroy_pipeline; - sgimgui_args_destroy_attachments_t destroy_attachments; - sgimgui_args_update_buffer_t update_buffer; - sgimgui_args_update_image_t update_image; - sgimgui_args_append_buffer_t append_buffer; - sgimgui_args_begin_pass_t begin_pass; - sgimgui_args_apply_viewport_t apply_viewport; - sgimgui_args_apply_scissor_rect_t apply_scissor_rect; - sgimgui_args_apply_pipeline_t apply_pipeline; - sgimgui_args_apply_bindings_t apply_bindings; - sgimgui_args_apply_uniforms_t apply_uniforms; - sgimgui_args_draw_t draw; - sgimgui_args_alloc_buffer_t alloc_buffer; - sgimgui_args_alloc_image_t alloc_image; - sgimgui_args_alloc_sampler_t alloc_sampler; - sgimgui_args_alloc_shader_t alloc_shader; - sgimgui_args_alloc_pipeline_t alloc_pipeline; - sgimgui_args_alloc_attachments_t alloc_attachments; - sgimgui_args_dealloc_buffer_t dealloc_buffer; - sgimgui_args_dealloc_image_t dealloc_image; - sgimgui_args_dealloc_sampler_t dealloc_sampler; - sgimgui_args_dealloc_shader_t dealloc_shader; - sgimgui_args_dealloc_pipeline_t dealloc_pipeline; - sgimgui_args_dealloc_attachments_t dealloc_attachments; - sgimgui_args_init_buffer_t init_buffer; - sgimgui_args_init_image_t init_image; - sgimgui_args_init_sampler_t init_sampler; - sgimgui_args_init_shader_t init_shader; - sgimgui_args_init_pipeline_t init_pipeline; - sgimgui_args_init_attachments_t init_attachments; - sgimgui_args_uninit_buffer_t uninit_buffer; - sgimgui_args_uninit_image_t uninit_image; - sgimgui_args_uninit_sampler_t uninit_sampler; - sgimgui_args_uninit_shader_t uninit_shader; - sgimgui_args_uninit_pipeline_t uninit_pipeline; - sgimgui_args_uninit_attachments_t uninit_attachments; - sgimgui_args_fail_buffer_t fail_buffer; - sgimgui_args_fail_image_t fail_image; - sgimgui_args_fail_sampler_t fail_sampler; - sgimgui_args_fail_shader_t fail_shader; - sgimgui_args_fail_pipeline_t fail_pipeline; - sgimgui_args_fail_attachments_t fail_attachments; - sgimgui_args_push_debug_group_t push_debug_group; -} sgimgui_args_t; - -typedef struct sgimgui_capture_item_t { - sgimgui_cmd_t cmd; - uint32_t color; - sgimgui_args_t args; -} sgimgui_capture_item_t; - -typedef struct sgimgui_capture_bucket_t { - size_t ubuf_size; /* size of uniform capture buffer in bytes */ - size_t ubuf_pos; /* current uniform buffer pos */ - uint8_t* ubuf; /* buffer for capturing uniform updates */ - int num_items; - sgimgui_capture_item_t items[sgimgui_MAX_FRAMECAPTURE_ITEMS]; -} sgimgui_capture_bucket_t; - -/* double-buffered call-capture buckets, one bucket is currently recorded, - the previous bucket is displayed -*/ -typedef struct sgimgui_capture_window_t { - bool open; - int bucket_index; /* which bucket to record to, 0 or 1 */ - int sel_item; /* currently selected capture item by index */ - sgimgui_capture_bucket_t bucket[2]; -} sgimgui_capture_window_t; - -typedef struct sgimgui_caps_window_t { - bool open; -} sgimgui_caps_window_t; - -typedef struct sgimgui_frame_stats_window_t { - bool open; - bool disable_sokol_imgui_stats; - bool in_sokol_imgui; - sg_frame_stats stats; - // FIXME: add a ringbuffer for a stats history here -} sgimgui_frame_stats_window_t; - -/* - sgimgui_allocator_t - - Used in sgimgui_desc_t to provide custom memory-alloc and -free functions - to sokol_gfx_imgui.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). -*/ -typedef struct sgimgui_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sgimgui_allocator_t; - -/* - sgimgui_desc_t - - Initialization options for sgimgui_init(). -*/ -typedef struct sgimgui_desc_t { - sgimgui_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) -} sgimgui_desc_t; - -typedef struct sgimgui_t { - uint32_t init_tag; - sgimgui_desc_t desc; - sgimgui_buffer_window_t buffer_window; - sgimgui_image_window_t image_window; - sgimgui_sampler_window_t sampler_window; - sgimgui_shader_window_t shader_window; - sgimgui_pipeline_window_t pipeline_window; - sgimgui_attachments_window_t attachments_window; - sgimgui_capture_window_t capture_window; - sgimgui_caps_window_t caps_window; - sgimgui_frame_stats_window_t frame_stats_window; - sg_pipeline cur_pipeline; - sg_trace_hooks hooks; -} sgimgui_t; - -SOKOL_GFX_IMGUI_API_DECL void sgimgui_init(sgimgui_t* ctx, const sgimgui_desc_t* desc); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_discard(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw(sgimgui_t* ctx); - -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_menu(sgimgui_t* ctx, const char* title); - -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_buffer_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_image_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_sampler_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_shader_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_pipeline_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_attachments_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_capture_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_capabilities_window_content(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_frame_stats_window_content(sgimgui_t* ctx); - -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_buffer_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_image_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_sampler_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_shader_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_pipeline_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_attachments_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_capture_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_capabilities_window(sgimgui_t* ctx); -SOKOL_GFX_IMGUI_API_DECL void sgimgui_draw_frame_stats_window(sgimgui_t* ctx); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif -#endif /* SOKOL_GFX_IMGUI_INCLUDED */ - -/*=== IMPLEMENTATION =========================================================*/ -#ifdef SOKOL_GFX_IMGUI_IMPL -#define SOKOL_GFX_IMGUI_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sgimgui_desc_t.allocator to override memory allocation functions" -#endif - -#if defined(__cplusplus) - #if !defined(IMGUI_VERSION) - #error "Please include imgui.h before the sokol_imgui.h implementation" - #endif -#else - #if !defined(CIMGUI_INCLUDED) - #error "Please include cimgui.h before the sokol_imgui.h implementation" - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif -#ifndef _SOKOL_UNUSED -#define _SOKOL_UNUSED(x) (void)(x) -#endif -#ifndef SOKOL_API_IMPL -#define SOKOL_API_IMPL -#endif - -#include -#include // snprintf -#include // malloc, free - -#define _SGIMGUI_SLOT_MASK (0xFFFF) -#define _SGIMGUI_LIST_WIDTH (192) -#define _SGIMGUI_COLOR_OTHER 0xFFCCCCCC -#define _SGIMGUI_COLOR_RSRC 0xFF00FFFF -#define _SGIMGUI_COLOR_PASS 0xFFFFFF00 -#define _SGIMGUI_COLOR_APPLY 0xFFCCCC00 -#define _SGIMGUI_COLOR_DRAW 0xFF00FF00 -#define _SGIMGUI_COLOR_ERR 0xFF8888FF - -/*--- C => C++ layer ---------------------------------------------------------*/ -#if defined(__cplusplus) -#define IMVEC2(x,y) ImVec2(x,y) -#define IMVEC4(x,y,z,w) ImVec4(x,y,z,w) -_SOKOL_PRIVATE void igText(const char* fmt,...) { - va_list args; - va_start(args, fmt); - ImGui::TextV(fmt, args); - va_end(args); -} -_SOKOL_PRIVATE void igSeparator() { - return ImGui::Separator(); -} -_SOKOL_PRIVATE void igSameLine(float offset_from_start_x, float spacing) { - return ImGui::SameLine(offset_from_start_x,spacing); -} -_SOKOL_PRIVATE void igPushID_Int(int int_id) { - return ImGui::PushID(int_id); -} -_SOKOL_PRIVATE void igPopID() { - return ImGui::PopID(); -} -_SOKOL_PRIVATE bool igSelectable_Bool(const char* label,bool selected,ImGuiSelectableFlags flags,const ImVec2 size) { - return ImGui::Selectable(label,selected,flags,size); -} -_SOKOL_PRIVATE bool igSmallButton(const char* label) { - return ImGui::SmallButton(label); -} -_SOKOL_PRIVATE bool igBeginChild_Str(const char* str_id,const ImVec2 size,bool border,ImGuiWindowFlags flags) { - return ImGui::BeginChild(str_id,size,border,flags); -} -_SOKOL_PRIVATE void igEndChild() { - return ImGui::EndChild(); -} -_SOKOL_PRIVATE void igPushStyleColor_U32(ImGuiCol idx, ImU32 col) { - return ImGui::PushStyleColor(idx,col); -} -_SOKOL_PRIVATE void igPopStyleColor(int count) { - return ImGui::PopStyleColor(count); -} -_SOKOL_PRIVATE bool igTreeNode_StrStr(const char* str_id,const char* fmt,...) { - va_list args; - va_start(args, fmt); - bool ret = ImGui::TreeNodeV(str_id,fmt,args); - va_end(args); - return ret; -} -_SOKOL_PRIVATE bool igTreeNode_Str(const char* label) { - return ImGui::TreeNode(label); -} -_SOKOL_PRIVATE void igTreePop() { - return ImGui::TreePop(); -} -_SOKOL_PRIVATE bool igIsItemHovered(ImGuiHoveredFlags flags) { - return ImGui::IsItemHovered(flags); -} -_SOKOL_PRIVATE void igSetTooltip(const char* fmt,...) { - va_list args; - va_start(args, fmt); - ImGui::SetTooltipV(fmt,args); - va_end(args); -} -_SOKOL_PRIVATE bool igSliderFloat(const char* label,float* v,float v_min,float v_max,const char* format,ImGuiSliderFlags flags) { - return ImGui::SliderFloat(label,v,v_min,v_max,format,flags); -} -_SOKOL_PRIVATE void igImage(ImTextureID user_texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,const ImVec4 tint_col,const ImVec4 border_col) { - return ImGui::Image(user_texture_id,size,uv0,uv1,tint_col,border_col); -} -_SOKOL_PRIVATE void igSetNextWindowSize(const ImVec2 size,ImGuiCond cond) { - return ImGui::SetNextWindowSize(size,cond); -} -_SOKOL_PRIVATE bool igBegin(const char* name,bool* p_open,ImGuiWindowFlags flags) { - return ImGui::Begin(name,p_open,flags); -} -_SOKOL_PRIVATE void igEnd() { - return ImGui::End(); -} -_SOKOL_PRIVATE bool igBeginMenu(const char* label, bool enabled) { - return ImGui::BeginMenu(label, enabled); -} -_SOKOL_PRIVATE void igEndMenu(void) { - ImGui::EndMenu(); -} -_SOKOL_PRIVATE bool igMenuItem_BoolPtr(const char* label, const char* shortcut, bool* p_selected, bool enabled) { - return ImGui::MenuItem(label, shortcut, p_selected, enabled); -} -_SOKOL_PRIVATE bool igBeginTable(const char* str_id, int column, ImGuiTableFlags flags, const ImVec2 outer_size, float inner_width) { - return ImGui::BeginTable(str_id, column, flags, outer_size, inner_width); -} -_SOKOL_PRIVATE void igEndTable(void) { - ImGui::EndTable(); -} -_SOKOL_PRIVATE void igTableSetupScrollFreeze(int cols, int rows) { - ImGui::TableSetupScrollFreeze(cols, rows); -} -_SOKOL_PRIVATE void igTableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) { - ImGui::TableSetupColumn(label, flags, init_width_or_weight, user_id); -} -_SOKOL_PRIVATE void igTableHeadersRow(void) { - ImGui::TableHeadersRow(); -} -_SOKOL_PRIVATE void igTableNextRow(ImGuiTableRowFlags row_flags, float min_row_height) { - ImGui::TableNextRow(row_flags, min_row_height); -} -_SOKOL_PRIVATE bool igTableSetColumnIndex(int column_n) { - return ImGui::TableSetColumnIndex(column_n); -} -_SOKOL_PRIVATE bool igCheckbox(const char* label, bool* v) { - return ImGui::Checkbox(label, v); -} -#else -#define IMVEC2(x,y) (ImVec2){x,y} -#define IMVEC4(x,y,z,w) (ImVec4){x,y,z,w} -#endif - -/*--- UTILS ------------------------------------------------------------------*/ -_SOKOL_PRIVATE void _sgimgui_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -_SOKOL_PRIVATE void* _sgimgui_malloc(const sgimgui_allocator_t* allocator, size_t size) { - SOKOL_ASSERT(allocator && (size > 0)); - void* ptr; - if (allocator->alloc_fn) { - ptr = allocator->alloc_fn(size, allocator->user_data); - } else { - ptr = malloc(size); - } - SOKOL_ASSERT(ptr); - return ptr; -} - -_SOKOL_PRIVATE void* _sgimgui_malloc_clear(const sgimgui_allocator_t* allocator, size_t size) { - void* ptr = _sgimgui_malloc(allocator, size); - _sgimgui_clear(ptr, size); - return ptr; -} - -_SOKOL_PRIVATE void _sgimgui_free(const sgimgui_allocator_t* allocator, void* ptr) { - SOKOL_ASSERT(allocator); - if (allocator->free_fn) { - allocator->free_fn(ptr, allocator->user_data); - } else { - free(ptr); - } -} - - _SOKOL_PRIVATE void* _sgimgui_realloc(const sgimgui_allocator_t* allocator, void* old_ptr, size_t old_size, size_t new_size) { - SOKOL_ASSERT(allocator && (new_size > 0) && (new_size > old_size)); - void* new_ptr = _sgimgui_malloc(allocator, new_size); - if (old_ptr) { - if (old_size > 0) { - memcpy(new_ptr, old_ptr, old_size); - } - _sgimgui_free(allocator, old_ptr); - } - return new_ptr; -} - -_SOKOL_PRIVATE int _sgimgui_slot_index(uint32_t id) { - int slot_index = (int) (id & _SGIMGUI_SLOT_MASK); - SOKOL_ASSERT(0 != slot_index); - return slot_index; -} - -_SOKOL_PRIVATE uint32_t _sgimgui_align_u32(uint32_t val, uint32_t align) { - SOKOL_ASSERT((align > 0) && ((align & (align - 1)) == 0)); - return (val + (align - 1)) & ~(align - 1); -} - -_SOKOL_PRIVATE uint32_t _sgimgui_std140_uniform_alignment(sg_uniform_type type, int array_count) { - SOKOL_ASSERT(array_count > 0); - if (array_count == 1) { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_INT: - return 4; - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_INT2: - return 8; - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT3: - case SG_UNIFORMTYPE_INT4: - return 16; - case SG_UNIFORMTYPE_MAT4: - return 16; - default: - SOKOL_UNREACHABLE; - return 1; - } - } else { - return 16; - } -} - -_SOKOL_PRIVATE uint32_t _sgimgui_std140_uniform_size(sg_uniform_type type, int array_count) { - SOKOL_ASSERT(array_count > 0); - if (array_count == 1) { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_INT: - return 4; - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_INT2: - return 8; - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_INT3: - return 12; - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT4: - return 16; - case SG_UNIFORMTYPE_MAT4: - return 64; - default: - SOKOL_UNREACHABLE; - return 0; - } - } else { - switch (type) { - case SG_UNIFORMTYPE_FLOAT: - case SG_UNIFORMTYPE_FLOAT2: - case SG_UNIFORMTYPE_FLOAT3: - case SG_UNIFORMTYPE_FLOAT4: - case SG_UNIFORMTYPE_INT: - case SG_UNIFORMTYPE_INT2: - case SG_UNIFORMTYPE_INT3: - case SG_UNIFORMTYPE_INT4: - return 16 * (uint32_t)array_count; - case SG_UNIFORMTYPE_MAT4: - return 64 * (uint32_t)array_count; - default: - SOKOL_UNREACHABLE; - return 0; - } - } -} - -_SOKOL_PRIVATE void _sgimgui_strcpy(sgimgui_str_t* dst, const char* src) { - SOKOL_ASSERT(dst); - if (src) { - #if defined(_MSC_VER) - strncpy_s(dst->buf, sgimgui_STRBUF_LEN, src, (sgimgui_STRBUF_LEN-1)); - #else - strncpy(dst->buf, src, sgimgui_STRBUF_LEN); - #endif - dst->buf[sgimgui_STRBUF_LEN-1] = 0; - } else { - _sgimgui_clear(dst->buf, sgimgui_STRBUF_LEN); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_make_str(const char* str) { - sgimgui_str_t res; - _sgimgui_strcpy(&res, str); - return res; -} - -_SOKOL_PRIVATE const char* _sgimgui_str_dup(const sgimgui_allocator_t* allocator, const char* src) { - SOKOL_ASSERT(allocator && src); - size_t len = strlen(src) + 1; - char* dst = (char*) _sgimgui_malloc(allocator, len); - memcpy(dst, src, len); - return (const char*) dst; -} - -_SOKOL_PRIVATE const void* _sgimgui_bin_dup(const sgimgui_allocator_t* allocator, const void* src, size_t num_bytes) { - SOKOL_ASSERT(allocator && src && (num_bytes > 0)); - void* dst = _sgimgui_malloc(allocator, num_bytes); - memcpy(dst, src, num_bytes); - return (const void*) dst; -} - -_SOKOL_PRIVATE void _sgimgui_snprintf(sgimgui_str_t* dst, const char* fmt, ...) { - SOKOL_ASSERT(dst); - va_list args; - va_start(args, fmt); - vsnprintf(dst->buf, sizeof(dst->buf), fmt, args); - dst->buf[sizeof(dst->buf)-1] = 0; - va_end(args); -} - -/*--- STRING CONVERSION ------------------------------------------------------*/ -_SOKOL_PRIVATE const char* _sgimgui_resourcestate_string(sg_resource_state s) { - switch (s) { - case SG_RESOURCESTATE_INITIAL: return "SG_RESOURCESTATE_INITIAL"; - case SG_RESOURCESTATE_ALLOC: return "SG_RESOURCESTATE_ALLOC"; - case SG_RESOURCESTATE_VALID: return "SG_RESOURCESTATE_VALID"; - case SG_RESOURCESTATE_FAILED: return "SG_RESOURCESTATE_FAILED"; - default: return "SG_RESOURCESTATE_INVALID"; - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_resource_slot(const sg_slot_info* slot) { - igText("ResId: %08X", slot->res_id); - igText("State: %s", _sgimgui_resourcestate_string(slot->state)); -} - -_SOKOL_PRIVATE const char* _sgimgui_backend_string(sg_backend b) { - switch (b) { - case SG_BACKEND_GLCORE: return "SG_BACKEND_GLCORE"; - case SG_BACKEND_GLES3: return "SG_BACKEND_GLES3"; - case SG_BACKEND_D3D11: return "SG_BACKEND_D3D11"; - case SG_BACKEND_METAL_IOS: return "SG_BACKEND_METAL_IOS"; - case SG_BACKEND_METAL_MACOS: return "SG_BACKEND_METAL_MACOS"; - case SG_BACKEND_METAL_SIMULATOR: return "SG_BACKEND_METAL_SIMULATOR"; - case SG_BACKEND_WGPU: return "SG_BACKEND_WGPU"; - case SG_BACKEND_DUMMY: return "SG_BACKEND_DUMMY"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_buffertype_string(sg_buffer_type t) { - switch (t) { - case SG_BUFFERTYPE_VERTEXBUFFER: return "SG_BUFFERTYPE_VERTEXBUFFER"; - case SG_BUFFERTYPE_INDEXBUFFER: return "SG_BUFFERTYPE_INDEXBUFFER"; - case SG_BUFFERTYPE_STORAGEBUFFER: return "SG_BUFFERTYPE_STORAGEBUFFER"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_usage_string(sg_usage u) { - switch (u) { - case SG_USAGE_IMMUTABLE: return "SG_USAGE_IMMUTABLE"; - case SG_USAGE_DYNAMIC: return "SG_USAGE_DYNAMIC"; - case SG_USAGE_STREAM: return "SG_USAGE_STREAM"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_imagetype_string(sg_image_type t) { - switch (t) { - case SG_IMAGETYPE_2D: return "SG_IMAGETYPE_2D"; - case SG_IMAGETYPE_CUBE: return "SG_IMAGETYPE_CUBE"; - case SG_IMAGETYPE_3D: return "SG_IMAGETYPE_3D"; - case SG_IMAGETYPE_ARRAY: return "SG_IMAGETYPE_ARRAY"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_imagesampletype_string(sg_image_sample_type t) { - switch (t) { - case SG_IMAGESAMPLETYPE_FLOAT: return "SG_IMAGESAMPLETYPE_FLOAT"; - case SG_IMAGESAMPLETYPE_DEPTH: return "SG_IMAGESAMPLETYPE_DEPTH"; - case SG_IMAGESAMPLETYPE_SINT: return "SG_IMAGESAMPLETYPE_SINT"; - case SG_IMAGESAMPLETYPE_UINT: return "SG_IMAGESAMPLETYPE_UINT"; - case SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT: return "SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_samplertype_string(sg_sampler_type t) { - switch (t) { - case SG_SAMPLERTYPE_FILTERING: return "SG_SAMPLERTYPE_FILTERING"; - case SG_SAMPLERTYPE_COMPARISON: return "SG_SAMPLERTYPE_COMPARISON"; - case SG_SAMPLERTYPE_NONFILTERING: return "SG_SAMPLERTYPE_NONFILTERING"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_uniformlayout_string(sg_uniform_layout l) { - switch (l) { - case SG_UNIFORMLAYOUT_NATIVE: return "SG_UNIFORMLAYOUT_NATIVE"; - case SG_UNIFORMLAYOUT_STD140: return "SG_UNIFORMLAYOUT_STD140"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_pixelformat_string(sg_pixel_format fmt) { - switch (fmt) { - case SG_PIXELFORMAT_NONE: return "SG_PIXELFORMAT_NONE"; - case SG_PIXELFORMAT_R8: return "SG_PIXELFORMAT_R8"; - case SG_PIXELFORMAT_R8SN: return "SG_PIXELFORMAT_R8SN"; - case SG_PIXELFORMAT_R8UI: return "SG_PIXELFORMAT_R8UI"; - case SG_PIXELFORMAT_R8SI: return "SG_PIXELFORMAT_R8SI"; - case SG_PIXELFORMAT_R16: return "SG_PIXELFORMAT_R16"; - case SG_PIXELFORMAT_R16SN: return "SG_PIXELFORMAT_R16SN"; - case SG_PIXELFORMAT_R16UI: return "SG_PIXELFORMAT_R16UI"; - case SG_PIXELFORMAT_R16SI: return "SG_PIXELFORMAT_R16SI"; - case SG_PIXELFORMAT_R16F: return "SG_PIXELFORMAT_R16F"; - case SG_PIXELFORMAT_RG8: return "SG_PIXELFORMAT_RG8"; - case SG_PIXELFORMAT_RG8SN: return "SG_PIXELFORMAT_RG8SN"; - case SG_PIXELFORMAT_RG8UI: return "SG_PIXELFORMAT_RG8UI"; - case SG_PIXELFORMAT_RG8SI: return "SG_PIXELFORMAT_RG8SI"; - case SG_PIXELFORMAT_R32UI: return "SG_PIXELFORMAT_R32UI"; - case SG_PIXELFORMAT_R32SI: return "SG_PIXELFORMAT_R32SI"; - case SG_PIXELFORMAT_R32F: return "SG_PIXELFORMAT_R32F"; - case SG_PIXELFORMAT_RG16: return "SG_PIXELFORMAT_RG16"; - case SG_PIXELFORMAT_RG16SN: return "SG_PIXELFORMAT_RG16SN"; - case SG_PIXELFORMAT_RG16UI: return "SG_PIXELFORMAT_RG16UI"; - case SG_PIXELFORMAT_RG16SI: return "SG_PIXELFORMAT_RG16SI"; - case SG_PIXELFORMAT_RG16F: return "SG_PIXELFORMAT_RG16F"; - case SG_PIXELFORMAT_RGBA8: return "SG_PIXELFORMAT_RGBA8"; - case SG_PIXELFORMAT_SRGB8A8: return "SG_PIXELFORMAT_SRGB8A8"; - case SG_PIXELFORMAT_RGBA8SN: return "SG_PIXELFORMAT_RGBA8SN"; - case SG_PIXELFORMAT_RGBA8UI: return "SG_PIXELFORMAT_RGBA8UI"; - case SG_PIXELFORMAT_RGBA8SI: return "SG_PIXELFORMAT_RGBA8SI"; - case SG_PIXELFORMAT_BGRA8: return "SG_PIXELFORMAT_BGRA8"; - case SG_PIXELFORMAT_RGB10A2: return "SG_PIXELFORMAT_RGB10A2"; - case SG_PIXELFORMAT_RG11B10F: return "SG_PIXELFORMAT_RG11B10F"; - case SG_PIXELFORMAT_RG32UI: return "SG_PIXELFORMAT_RG32UI"; - case SG_PIXELFORMAT_RG32SI: return "SG_PIXELFORMAT_RG32SI"; - case SG_PIXELFORMAT_RG32F: return "SG_PIXELFORMAT_RG32F"; - case SG_PIXELFORMAT_RGBA16: return "SG_PIXELFORMAT_RGBA16"; - case SG_PIXELFORMAT_RGBA16SN: return "SG_PIXELFORMAT_RGBA16SN"; - case SG_PIXELFORMAT_RGBA16UI: return "SG_PIXELFORMAT_RGBA16UI"; - case SG_PIXELFORMAT_RGBA16SI: return "SG_PIXELFORMAT_RGBA16SI"; - case SG_PIXELFORMAT_RGBA16F: return "SG_PIXELFORMAT_RGBA16F"; - case SG_PIXELFORMAT_RGBA32UI: return "SG_PIXELFORMAT_RGBA32UI"; - case SG_PIXELFORMAT_RGBA32SI: return "SG_PIXELFORMAT_RGBA32SI"; - case SG_PIXELFORMAT_RGBA32F: return "SG_PIXELFORMAT_RGBA32F"; - case SG_PIXELFORMAT_DEPTH: return "SG_PIXELFORMAT_DEPTH"; - case SG_PIXELFORMAT_DEPTH_STENCIL: return "SG_PIXELFORMAT_DEPTH_STENCIL"; - case SG_PIXELFORMAT_BC1_RGBA: return "SG_PIXELFORMAT_BC1_RGBA"; - case SG_PIXELFORMAT_BC2_RGBA: return "SG_PIXELFORMAT_BC2_RGBA"; - case SG_PIXELFORMAT_BC3_RGBA: return "SG_PIXELFORMAT_BC3_RGBA"; - case SG_PIXELFORMAT_BC4_R: return "SG_PIXELFORMAT_BC4_R"; - case SG_PIXELFORMAT_BC4_RSN: return "SG_PIXELFORMAT_BC4_RSN"; - case SG_PIXELFORMAT_BC5_RG: return "SG_PIXELFORMAT_BC5_RG"; - case SG_PIXELFORMAT_BC5_RGSN: return "SG_PIXELFORMAT_BC5_RGSN"; - case SG_PIXELFORMAT_BC6H_RGBF: return "SG_PIXELFORMAT_BC6H_RGBF"; - case SG_PIXELFORMAT_BC6H_RGBUF: return "SG_PIXELFORMAT_BC6H_RGBUF"; - case SG_PIXELFORMAT_BC7_RGBA: return "SG_PIXELFORMAT_BC7_RGBA"; - case SG_PIXELFORMAT_PVRTC_RGB_2BPP: return "SG_PIXELFORMAT_PVRTC_RGB_2BPP"; - case SG_PIXELFORMAT_PVRTC_RGB_4BPP: return "SG_PIXELFORMAT_PVRTC_RGB_4BPP"; - case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: return "SG_PIXELFORMAT_PVRTC_RGBA_2BPP"; - case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: return "SG_PIXELFORMAT_PVRTC_RGBA_4BPP"; - case SG_PIXELFORMAT_ETC2_RGB8: return "SG_PIXELFORMAT_ETC2_RGB8"; - case SG_PIXELFORMAT_ETC2_RGB8A1: return "SG_PIXELFORMAT_ETC2_RGB8A1"; - case SG_PIXELFORMAT_ETC2_RGBA8: return "SG_PIXELFORMAT_ETC2_RGBA8"; - case SG_PIXELFORMAT_EAC_R11: return "SG_PIXELFORMAT_EAC_R11"; - case SG_PIXELFORMAT_EAC_R11SN: return "SG_PIXELFORMAT_EAC_R11SN"; - case SG_PIXELFORMAT_EAC_RG11: return "SG_PIXELFORMAT_EAC_RG11"; - case SG_PIXELFORMAT_EAC_RG11SN: return "SG_PIXELFORMAT_EAC_RG11SN"; - case SG_PIXELFORMAT_RGB9E5: return "SG_PIXELFORMAT_RGB9E5"; - case SG_PIXELFORMAT_BC3_SRGBA: return "SG_PIXELFORMAT_BC3_SRGBA"; - case SG_PIXELFORMAT_BC7_SRGBA: return "SG_PIXELFORMAT_BC7_SRGBA"; - case SG_PIXELFORMAT_ETC2_SRGB8: return "SG_PIXELFORMAT_ETC2_SRGB8"; - case SG_PIXELFORMAT_ETC2_SRGB8A8: return "SG_PIXELFORMAT_ETC2_SRGB8A8"; - case SG_PIXELFORMAT_ASTC_4x4_RGBA: return "SG_PIXELFORMAT_ASTC_4x4_RGBA"; - case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return "SG_PIXELFORMAT_ASTC_4x4_SRGBA"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_filter_string(sg_filter f) { - switch (f) { - case SG_FILTER_NEAREST: return "SG_FILTER_NEAREST"; - case SG_FILTER_LINEAR: return "SG_FILTER_LINEAR"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_wrap_string(sg_wrap w) { - switch (w) { - case SG_WRAP_REPEAT: return "SG_WRAP_REPEAT"; - case SG_WRAP_CLAMP_TO_EDGE: return "SG_WRAP_CLAMP_TO_EDGE"; - case SG_WRAP_CLAMP_TO_BORDER: return "SG_WRAP_CLAMP_TO_BORDER"; - case SG_WRAP_MIRRORED_REPEAT: return "SG_WRAP_MIRRORED_REPEAT"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_bordercolor_string(sg_border_color bc) { - switch (bc) { - case SG_BORDERCOLOR_TRANSPARENT_BLACK: return "SG_BORDERCOLOR_TRANSPARENT_BLACK"; - case SG_BORDERCOLOR_OPAQUE_BLACK: return "SG_BORDERCOLOR_OPAQUE_BLACK"; - case SG_BORDERCOLOR_OPAQUE_WHITE: return "SG_BORDERCOLOR_OPAQUE_WHITE"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_uniformtype_string(sg_uniform_type t) { - switch (t) { - case SG_UNIFORMTYPE_FLOAT: return "SG_UNIFORMTYPE_FLOAT"; - case SG_UNIFORMTYPE_FLOAT2: return "SG_UNIFORMTYPE_FLOAT2"; - case SG_UNIFORMTYPE_FLOAT3: return "SG_UNIFORMTYPE_FLOAT3"; - case SG_UNIFORMTYPE_FLOAT4: return "SG_UNIFORMTYPE_FLOAT4"; - case SG_UNIFORMTYPE_INT: return "SG_UNIFORMTYPE_INT"; - case SG_UNIFORMTYPE_INT2: return "SG_UNIFORMTYPE_INT2"; - case SG_UNIFORMTYPE_INT3: return "SG_UNIFORMTYPE_INT3"; - case SG_UNIFORMTYPE_INT4: return "SG_UNIFORMTYPE_INT4"; - case SG_UNIFORMTYPE_MAT4: return "SG_UNIFORMTYPE_MAT4"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_vertexstep_string(sg_vertex_step s) { - switch (s) { - case SG_VERTEXSTEP_PER_VERTEX: return "SG_VERTEXSTEP_PER_VERTEX"; - case SG_VERTEXSTEP_PER_INSTANCE: return "SG_VERTEXSTEP_PER_INSTANCE"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_vertexformat_string(sg_vertex_format f) { - switch (f) { - case SG_VERTEXFORMAT_FLOAT: return "SG_VERTEXFORMAT_FLOAT"; - case SG_VERTEXFORMAT_FLOAT2: return "SG_VERTEXFORMAT_FLOAT2"; - case SG_VERTEXFORMAT_FLOAT3: return "SG_VERTEXFORMAT_FLOAT3"; - case SG_VERTEXFORMAT_FLOAT4: return "SG_VERTEXFORMAT_FLOAT4"; - case SG_VERTEXFORMAT_BYTE4: return "SG_VERTEXFORMAT_BYTE4"; - case SG_VERTEXFORMAT_BYTE4N: return "SG_VERTEXFORMAT_BYTE4N"; - case SG_VERTEXFORMAT_UBYTE4: return "SG_VERTEXFORMAT_UBYTE4"; - case SG_VERTEXFORMAT_UBYTE4N: return "SG_VERTEXFORMAT_UBYTE4N"; - case SG_VERTEXFORMAT_SHORT2: return "SG_VERTEXFORMAT_SHORT2"; - case SG_VERTEXFORMAT_SHORT2N: return "SG_VERTEXFORMAT_SHORT2N"; - case SG_VERTEXFORMAT_USHORT2N: return "SG_VERTEXFORMAT_USHORT2N"; - case SG_VERTEXFORMAT_SHORT4: return "SG_VERTEXFORMAT_SHORT4"; - case SG_VERTEXFORMAT_SHORT4N: return "SG_VERTEXFORMAT_SHORT4N"; - case SG_VERTEXFORMAT_USHORT4N: return "SG_VERTEXFORMAT_USHORT4N"; - case SG_VERTEXFORMAT_UINT10_N2: return "SG_VERTEXFORMAT_UINT10_N2"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_primitivetype_string(sg_primitive_type t) { - switch (t) { - case SG_PRIMITIVETYPE_POINTS: return "SG_PRIMITIVETYPE_POINTS"; - case SG_PRIMITIVETYPE_LINES: return "SG_PRIMITIVETYPE_LINES"; - case SG_PRIMITIVETYPE_LINE_STRIP: return "SG_PRIMITIVETYPE_LINE_STRIP"; - case SG_PRIMITIVETYPE_TRIANGLES: return "SG_PRIMITIVETYPE_TRIANGLES"; - case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return "SG_PRIMITIVETYPE_TRIANGLE_STRIP"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_indextype_string(sg_index_type t) { - switch (t) { - case SG_INDEXTYPE_NONE: return "SG_INDEXTYPE_NONE"; - case SG_INDEXTYPE_UINT16: return "SG_INDEXTYPE_UINT16"; - case SG_INDEXTYPE_UINT32: return "SG_INDEXTYPE_UINT32"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_stencilop_string(sg_stencil_op op) { - switch (op) { - case SG_STENCILOP_KEEP: return "SG_STENCILOP_KEEP"; - case SG_STENCILOP_ZERO: return "SG_STENCILOP_ZERO"; - case SG_STENCILOP_REPLACE: return "SG_STENCILOP_REPLACE"; - case SG_STENCILOP_INCR_CLAMP: return "SG_STENCILOP_INCR_CLAMP"; - case SG_STENCILOP_DECR_CLAMP: return "SG_STENCILOP_DECR_CLAMP"; - case SG_STENCILOP_INVERT: return "SG_STENCILOP_INVERT"; - case SG_STENCILOP_INCR_WRAP: return "SG_STENCILOP_INCR_WRAP"; - case SG_STENCILOP_DECR_WRAP: return "SG_STENCILOP_DECR_WRAP"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_comparefunc_string(sg_compare_func f) { - switch (f) { - case SG_COMPAREFUNC_NEVER: return "SG_COMPAREFUNC_NEVER"; - case SG_COMPAREFUNC_LESS: return "SG_COMPAREFUNC_LESS"; - case SG_COMPAREFUNC_EQUAL: return "SG_COMPAREFUNC_EQUAL"; - case SG_COMPAREFUNC_LESS_EQUAL: return "SG_COMPAREFUNC_LESS_EQUAL"; - case SG_COMPAREFUNC_GREATER: return "SG_COMPAREFUNC_GREATER"; - case SG_COMPAREFUNC_NOT_EQUAL: return "SG_COMPAREFUNC_NOT_EQUAL"; - case SG_COMPAREFUNC_GREATER_EQUAL: return "SG_COMPAREFUNC_GREATER_EQUAL"; - case SG_COMPAREFUNC_ALWAYS: return "SG_COMPAREFUNC_ALWAYS"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_blendfactor_string(sg_blend_factor f) { - switch (f) { - case SG_BLENDFACTOR_ZERO: return "SG_BLENDFACTOR_ZERO"; - case SG_BLENDFACTOR_ONE: return "SG_BLENDFACTOR_ONE"; - case SG_BLENDFACTOR_SRC_COLOR: return "SG_BLENDFACTOR_SRC_COLOR"; - case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return "SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR"; - case SG_BLENDFACTOR_SRC_ALPHA: return "SG_BLENDFACTOR_SRC_ALPHA"; - case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return "SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA"; - case SG_BLENDFACTOR_DST_COLOR: return "SG_BLENDFACTOR_DST_COLOR"; - case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return "SG_BLENDFACTOR_ONE_MINUS_DST_COLOR"; - case SG_BLENDFACTOR_DST_ALPHA: return "SG_BLENDFACTOR_DST_ALPHA"; - case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return "SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA"; - case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return "SG_BLENDFACTOR_SRC_ALPHA_SATURATED"; - case SG_BLENDFACTOR_BLEND_COLOR: return "SG_BLENDFACTOR_BLEND_COLOR"; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return "SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR"; - case SG_BLENDFACTOR_BLEND_ALPHA: return "SG_BLENDFACTOR_BLEND_ALPHA"; - case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return "SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_blendop_string(sg_blend_op op) { - switch (op) { - case SG_BLENDOP_ADD: return "SG_BLENDOP_ADD"; - case SG_BLENDOP_SUBTRACT: return "SG_BLENDOP_SUBTRACT"; - case SG_BLENDOP_REVERSE_SUBTRACT: return "SG_BLENDOP_REVERSE_SUBTRACT"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_colormask_string(sg_color_mask m) { - static const char* str[] = { - "NONE", - "R", - "G", - "RG", - "B", - "RB", - "GB", - "RGB", - "A", - "RA", - "GA", - "RGA", - "BA", - "RBA", - "GBA", - "RGBA", - }; - return str[m & 0xF]; -} - -_SOKOL_PRIVATE const char* _sgimgui_cullmode_string(sg_cull_mode cm) { - switch (cm) { - case SG_CULLMODE_NONE: return "SG_CULLMODE_NONE"; - case SG_CULLMODE_FRONT: return "SG_CULLMODE_FRONT"; - case SG_CULLMODE_BACK: return "SG_CULLMODE_BACK"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_facewinding_string(sg_face_winding fw) { - switch (fw) { - case SG_FACEWINDING_CCW: return "SG_FACEWINDING_CCW"; - case SG_FACEWINDING_CW: return "SG_FACEWINDING_CW"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_shaderstage_string(sg_shader_stage stage) { - switch (stage) { - case SG_SHADERSTAGE_VS: return "SG_SHADERSTAGE_VS"; - case SG_SHADERSTAGE_FS: return "SG_SHADERSTAGE_FS"; - default: return "???"; - } -} - -_SOKOL_PRIVATE const char* _sgimgui_bool_string(bool b) { - return b ? "true" : "false"; -} - -_SOKOL_PRIVATE const char* _sgimgui_color_string(sgimgui_str_t* dst_str, sg_color color) { - _sgimgui_snprintf(dst_str, "%.3f %.3f %.3f %.3f", color.r, color.g, color.b, color.a); - return dst_str->buf; -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_res_id_string(uint32_t res_id, const char* label) { - SOKOL_ASSERT(label); - sgimgui_str_t res; - if (label[0]) { - _sgimgui_snprintf(&res, "'%s'", label); - } else { - _sgimgui_snprintf(&res, "0x%08X", res_id); - } - return res; -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_buffer_id_string(sgimgui_t* ctx, sg_buffer buf_id) { - if (buf_id.id != SG_INVALID_ID) { - const sgimgui_buffer_t* buf_ui = &ctx->buffer_window.slots[_sgimgui_slot_index(buf_id.id)]; - return _sgimgui_res_id_string(buf_id.id, buf_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_image_id_string(sgimgui_t* ctx, sg_image img_id) { - if (img_id.id != SG_INVALID_ID) { - const sgimgui_image_t* img_ui = &ctx->image_window.slots[_sgimgui_slot_index(img_id.id)]; - return _sgimgui_res_id_string(img_id.id, img_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_sampler_id_string(sgimgui_t* ctx, sg_sampler smp_id) { - if (smp_id.id != SG_INVALID_ID) { - const sgimgui_sampler_t* smp_ui = &ctx->sampler_window.slots[_sgimgui_slot_index(smp_id.id)]; - return _sgimgui_res_id_string(smp_id.id, smp_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_shader_id_string(sgimgui_t* ctx, sg_shader shd_id) { - if (shd_id.id != SG_INVALID_ID) { - const sgimgui_shader_t* shd_ui = &ctx->shader_window.slots[_sgimgui_slot_index(shd_id.id)]; - return _sgimgui_res_id_string(shd_id.id, shd_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_pipeline_id_string(sgimgui_t* ctx, sg_pipeline pip_id) { - if (pip_id.id != SG_INVALID_ID) { - const sgimgui_pipeline_t* pip_ui = &ctx->pipeline_window.slots[_sgimgui_slot_index(pip_id.id)]; - return _sgimgui_res_id_string(pip_id.id, pip_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_attachments_id_string(sgimgui_t* ctx, sg_attachments atts_id) { - if (atts_id.id != SG_INVALID_ID) { - const sgimgui_attachments_t* atts_ui = &ctx->attachments_window.slots[_sgimgui_slot_index(atts_id.id)]; - return _sgimgui_res_id_string(atts_id.id, atts_ui->label.buf); - } else { - return _sgimgui_make_str(""); - } -} - -/*--- RESOURCE HELPERS -------------------------------------------------------*/ -_SOKOL_PRIVATE void _sgimgui_buffer_created(sgimgui_t* ctx, sg_buffer res_id, int slot_index, const sg_buffer_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->buffer_window.num_slots)); - sgimgui_buffer_t* buf = &ctx->buffer_window.slots[slot_index]; - buf->res_id = res_id; - buf->desc = *desc; - buf->label = _sgimgui_make_str(desc->label); -} - -_SOKOL_PRIVATE void _sgimgui_buffer_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->buffer_window.num_slots)); - sgimgui_buffer_t* buf = &ctx->buffer_window.slots[slot_index]; - buf->res_id.id = SG_INVALID_ID; -} - -_SOKOL_PRIVATE void _sgimgui_image_created(sgimgui_t* ctx, sg_image res_id, int slot_index, const sg_image_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->image_window.num_slots)); - sgimgui_image_t* img = &ctx->image_window.slots[slot_index]; - img->res_id = res_id; - img->desc = *desc; - img->ui_scale = 1.0f; - img->label = _sgimgui_make_str(desc->label); - simgui_image_desc_t simgui_img_desc; - _sgimgui_clear(&simgui_img_desc, sizeof(simgui_img_desc)); - simgui_img_desc.image = res_id; - // keep sampler at default, which will use sokol_imgui.h's default nearest-filtering sampler - img->simgui_img = simgui_make_image(&simgui_img_desc); -} - -_SOKOL_PRIVATE void _sgimgui_image_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->image_window.num_slots)); - sgimgui_image_t* img = &ctx->image_window.slots[slot_index]; - img->res_id.id = SG_INVALID_ID; - simgui_destroy_image(img->simgui_img); -} - -_SOKOL_PRIVATE void _sgimgui_sampler_created(sgimgui_t* ctx, sg_sampler res_id, int slot_index, const sg_sampler_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->sampler_window.num_slots)); - sgimgui_sampler_t* smp = &ctx->sampler_window.slots[slot_index]; - smp->res_id = res_id; - smp->desc = *desc; - smp->label = _sgimgui_make_str(desc->label); -} - -_SOKOL_PRIVATE void _sgimgui_sampler_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->sampler_window.num_slots)); - sgimgui_sampler_t* smp = &ctx->sampler_window.slots[slot_index]; - smp->res_id.id = SG_INVALID_ID; -} - -_SOKOL_PRIVATE void _sgimgui_shader_created(sgimgui_t* ctx, sg_shader res_id, int slot_index, const sg_shader_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->shader_window.num_slots)); - sgimgui_shader_t* shd = &ctx->shader_window.slots[slot_index]; - shd->res_id = res_id; - shd->desc = *desc; - shd->label = _sgimgui_make_str(desc->label); - if (shd->desc.vs.entry) { - shd->vs_entry = _sgimgui_make_str(shd->desc.vs.entry); - shd->desc.vs.entry = shd->vs_entry.buf; - } - if (shd->desc.fs.entry) { - shd->fs_entry = _sgimgui_make_str(shd->desc.fs.entry); - shd->desc.fs.entry = shd->fs_entry.buf; - } - if (shd->desc.vs.d3d11_target) { - shd->vs_d3d11_target = _sgimgui_make_str(shd->desc.vs.d3d11_target); - shd->desc.fs.d3d11_target = shd->vs_d3d11_target.buf; - } - if (shd->desc.fs.d3d11_target) { - shd->fs_d3d11_target = _sgimgui_make_str(shd->desc.fs.d3d11_target); - shd->desc.fs.d3d11_target = shd->fs_d3d11_target.buf; - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_UBS; i++) { - for (int j = 0; j < SG_MAX_UB_MEMBERS; j++) { - sg_shader_uniform_desc* ud = &shd->desc.vs.uniform_blocks[i].uniforms[j]; - if (ud->name) { - shd->vs_uniform_name[i][j] = _sgimgui_make_str(ud->name); - ud->name = shd->vs_uniform_name[i][j].buf; - } - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_UBS; i++) { - for (int j = 0; j < SG_MAX_UB_MEMBERS; j++) { - sg_shader_uniform_desc* ud = &shd->desc.fs.uniform_blocks[i].uniforms[j]; - if (ud->name) { - shd->fs_uniform_name[i][j] = _sgimgui_make_str(ud->name); - ud->name = shd->fs_uniform_name[i][j].buf; - } - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS; i++) { - if (shd->desc.vs.image_sampler_pairs[i].glsl_name) { - shd->vs_image_sampler_name[i] = _sgimgui_make_str(shd->desc.vs.image_sampler_pairs[i].glsl_name); - shd->desc.vs.image_sampler_pairs[i].glsl_name = shd->vs_image_sampler_name[i].buf; - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS; i++) { - if (shd->desc.fs.image_sampler_pairs[i].glsl_name) { - shd->fs_image_sampler_name[i] = _sgimgui_make_str(shd->desc.fs.image_sampler_pairs[i].glsl_name); - shd->desc.fs.image_sampler_pairs[i].glsl_name = shd->fs_image_sampler_name[i].buf; - } - } - if (shd->desc.vs.source) { - shd->desc.vs.source = _sgimgui_str_dup(&ctx->desc.allocator, shd->desc.vs.source); - } - if (shd->desc.vs.bytecode.ptr) { - shd->desc.vs.bytecode.ptr = _sgimgui_bin_dup(&ctx->desc.allocator, shd->desc.vs.bytecode.ptr, shd->desc.vs.bytecode.size); - } - if (shd->desc.fs.source) { - shd->desc.fs.source = _sgimgui_str_dup(&ctx->desc.allocator, shd->desc.fs.source); - } - if (shd->desc.fs.bytecode.ptr) { - shd->desc.fs.bytecode.ptr = _sgimgui_bin_dup(&ctx->desc.allocator, shd->desc.fs.bytecode.ptr, shd->desc.fs.bytecode.size); - } - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - sg_shader_attr_desc* ad = &shd->desc.attrs[i]; - if (ad->name) { - shd->attr_name[i] = _sgimgui_make_str(ad->name); - ad->name = shd->attr_name[i].buf; - } - if (ad->sem_name) { - shd->attr_sem_name[i] = _sgimgui_make_str(ad->sem_name); - ad->sem_name = shd->attr_sem_name[i].buf; - } - } -} - -_SOKOL_PRIVATE void _sgimgui_shader_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->shader_window.num_slots)); - sgimgui_shader_t* shd = &ctx->shader_window.slots[slot_index]; - shd->res_id.id = SG_INVALID_ID; - if (shd->desc.vs.source) { - _sgimgui_free(&ctx->desc.allocator, (void*)shd->desc.vs.source); - shd->desc.vs.source = 0; - } - if (shd->desc.vs.bytecode.ptr) { - _sgimgui_free(&ctx->desc.allocator, (void*)shd->desc.vs.bytecode.ptr); - shd->desc.vs.bytecode.ptr = 0; - } - if (shd->desc.fs.source) { - _sgimgui_free(&ctx->desc.allocator, (void*)shd->desc.fs.source); - shd->desc.fs.source = 0; - } - if (shd->desc.fs.bytecode.ptr) { - _sgimgui_free(&ctx->desc.allocator, (void*)shd->desc.fs.bytecode.ptr); - shd->desc.fs.bytecode.ptr = 0; - } -} - -_SOKOL_PRIVATE void _sgimgui_pipeline_created(sgimgui_t* ctx, sg_pipeline res_id, int slot_index, const sg_pipeline_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->pipeline_window.num_slots)); - sgimgui_pipeline_t* pip = &ctx->pipeline_window.slots[slot_index]; - pip->res_id = res_id; - pip->label = _sgimgui_make_str(desc->label); - pip->desc = *desc; - -} - -_SOKOL_PRIVATE void _sgimgui_pipeline_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->pipeline_window.num_slots)); - sgimgui_pipeline_t* pip = &ctx->pipeline_window.slots[slot_index]; - pip->res_id.id = SG_INVALID_ID; -} - -_SOKOL_PRIVATE void _sgimgui_attachments_created(sgimgui_t* ctx, sg_attachments res_id, int slot_index, const sg_attachments_desc* desc) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->attachments_window.num_slots)); - sgimgui_attachments_t* atts = &ctx->attachments_window.slots[slot_index]; - atts->res_id = res_id; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - atts->color_image_scale[i] = 0.25f; - atts->resolve_image_scale[i] = 0.25f; - } - atts->ds_image_scale = 0.25f; - atts->label = _sgimgui_make_str(desc->label); - atts->desc = *desc; -} - -_SOKOL_PRIVATE void _sgimgui_attachments_destroyed(sgimgui_t* ctx, int slot_index) { - SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->attachments_window.num_slots)); - sgimgui_attachments_t* atts = &ctx->attachments_window.slots[slot_index]; - atts->res_id.id = SG_INVALID_ID; -} - -/*--- COMMAND CAPTURING ------------------------------------------------------*/ -_SOKOL_PRIVATE void _sgimgui_capture_init(sgimgui_t* ctx) { - const size_t ubuf_initial_size = 256 * 1024; - for (int i = 0; i < 2; i++) { - sgimgui_capture_bucket_t* bucket = &ctx->capture_window.bucket[i]; - bucket->ubuf_size = ubuf_initial_size; - bucket->ubuf = (uint8_t*) _sgimgui_malloc(&ctx->desc.allocator, bucket->ubuf_size); - } -} - -_SOKOL_PRIVATE void _sgimgui_capture_discard(sgimgui_t* ctx) { - for (int i = 0; i < 2; i++) { - sgimgui_capture_bucket_t* bucket = &ctx->capture_window.bucket[i]; - SOKOL_ASSERT(bucket->ubuf); - _sgimgui_free(&ctx->desc.allocator, bucket->ubuf); - bucket->ubuf = 0; - } -} - -_SOKOL_PRIVATE sgimgui_capture_bucket_t* _sgimgui_capture_get_write_bucket(sgimgui_t* ctx) { - return &ctx->capture_window.bucket[ctx->capture_window.bucket_index & 1]; -} - -_SOKOL_PRIVATE sgimgui_capture_bucket_t* _sgimgui_capture_get_read_bucket(sgimgui_t* ctx) { - return &ctx->capture_window.bucket[(ctx->capture_window.bucket_index + 1) & 1]; -} - -_SOKOL_PRIVATE void _sgimgui_capture_next_frame(sgimgui_t* ctx) { - ctx->capture_window.bucket_index = (ctx->capture_window.bucket_index + 1) & 1; - sgimgui_capture_bucket_t* bucket = &ctx->capture_window.bucket[ctx->capture_window.bucket_index]; - bucket->num_items = 0; - bucket->ubuf_pos = 0; -} - -_SOKOL_PRIVATE void _sgimgui_capture_grow_ubuf(sgimgui_t* ctx, size_t required_size) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_write_bucket(ctx); - SOKOL_ASSERT(required_size > bucket->ubuf_size); - size_t old_size = bucket->ubuf_size; - size_t new_size = required_size + (required_size>>1); /* allocate a bit ahead */ - bucket->ubuf_size = new_size; - bucket->ubuf = (uint8_t*) _sgimgui_realloc(&ctx->desc.allocator, bucket->ubuf, old_size, new_size); -} - -_SOKOL_PRIVATE sgimgui_capture_item_t* _sgimgui_capture_next_write_item(sgimgui_t* ctx) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_write_bucket(ctx); - if (bucket->num_items < sgimgui_MAX_FRAMECAPTURE_ITEMS) { - sgimgui_capture_item_t* item = &bucket->items[bucket->num_items++]; - return item; - } else { - return 0; - } -} - -_SOKOL_PRIVATE int _sgimgui_capture_num_read_items(sgimgui_t* ctx) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_read_bucket(ctx); - return bucket->num_items; -} - -_SOKOL_PRIVATE sgimgui_capture_item_t* _sgimgui_capture_read_item_at(sgimgui_t* ctx, int index) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_read_bucket(ctx); - SOKOL_ASSERT(index < bucket->num_items); - return &bucket->items[index]; -} - -_SOKOL_PRIVATE size_t _sgimgui_capture_uniforms(sgimgui_t* ctx, const sg_range* data) { - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_write_bucket(ctx); - const size_t required_size = bucket->ubuf_pos + data->size; - if (required_size > bucket->ubuf_size) { - _sgimgui_capture_grow_ubuf(ctx, required_size); - } - SOKOL_ASSERT(required_size <= bucket->ubuf_size); - memcpy(bucket->ubuf + bucket->ubuf_pos, data->ptr, data->size); - const size_t pos = bucket->ubuf_pos; - bucket->ubuf_pos += data->size; - SOKOL_ASSERT(bucket->ubuf_pos <= bucket->ubuf_size); - return pos; -} - -_SOKOL_PRIVATE sgimgui_str_t _sgimgui_capture_item_string(sgimgui_t* ctx, int index, const sgimgui_capture_item_t* item) { - sgimgui_str_t str = _sgimgui_make_str(0); - switch (item->cmd) { - case SGIMGUI_CMD_RESET_STATE_CACHE: - _sgimgui_snprintf(&str, "%d: sg_reset_state_cache()", index); - break; - - case SGIMGUI_CMD_MAKE_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.make_buffer.result); - _sgimgui_snprintf(&str, "%d: sg_make_buffer(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_MAKE_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.make_image.result); - _sgimgui_snprintf(&str, "%d: sg_make_image(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_MAKE_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.make_sampler.result); - _sgimgui_snprintf(&str, "%d: sg_make_sampler(desc=..) => %s", index, res_id.buf); - } - break; - case SGIMGUI_CMD_MAKE_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.make_shader.result); - _sgimgui_snprintf(&str, "%d: sg_make_shader(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_MAKE_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.make_pipeline.result); - _sgimgui_snprintf(&str, "%d: sg_make_pipeline(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_MAKE_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.make_attachments.result); - _sgimgui_snprintf(&str, "%d: sg_make_attachments(desc=..) => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.destroy_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_destroy_buffer(buf=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.destroy_image.image); - _sgimgui_snprintf(&str, "%d: sg_destroy_image(img=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.destroy_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_destroy_sampler(smp=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.destroy_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_destroy_shader(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.destroy_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_destroy_pipeline(pip=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DESTROY_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.destroy_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_destroy_attachments(atts=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UPDATE_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.update_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_update_buffer(buf=%s, data.size=%d)", - index, res_id.buf, - item->args.update_buffer.data_size); - } - break; - - case SGIMGUI_CMD_UPDATE_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.update_image.image); - _sgimgui_snprintf(&str, "%d: sg_update_image(img=%s, data=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_APPEND_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.append_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_append_buffer(buf=%s, data.size=%d) => %d", - index, res_id.buf, - item->args.append_buffer.data_size, - item->args.append_buffer.result); - } - break; - - case SGIMGUI_CMD_BEGIN_PASS: - { - _sgimgui_snprintf(&str, "%d: sg_begin_pass(pass=...)", index); - } - break; - - case SGIMGUI_CMD_APPLY_VIEWPORT: - _sgimgui_snprintf(&str, "%d: sg_apply_viewport(x=%d, y=%d, width=%d, height=%d, origin_top_left=%s)", - index, - item->args.apply_viewport.x, - item->args.apply_viewport.y, - item->args.apply_viewport.width, - item->args.apply_viewport.height, - _sgimgui_bool_string(item->args.apply_viewport.origin_top_left)); - break; - - case SGIMGUI_CMD_APPLY_SCISSOR_RECT: - _sgimgui_snprintf(&str, "%d: sg_apply_scissor_rect(x=%d, y=%d, width=%d, height=%d, origin_top_left=%s)", - index, - item->args.apply_scissor_rect.x, - item->args.apply_scissor_rect.y, - item->args.apply_scissor_rect.width, - item->args.apply_scissor_rect.height, - _sgimgui_bool_string(item->args.apply_scissor_rect.origin_top_left)); - break; - - case SGIMGUI_CMD_APPLY_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.apply_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_apply_pipeline(pip=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_APPLY_BINDINGS: - _sgimgui_snprintf(&str, "%d: sg_apply_bindings(bindings=..)", index); - break; - - case SGIMGUI_CMD_APPLY_UNIFORMS: - _sgimgui_snprintf(&str, "%d: sg_apply_uniforms(stage=%s, ub_index=%d, data.size=%d)", - index, - _sgimgui_shaderstage_string(item->args.apply_uniforms.stage), - item->args.apply_uniforms.ub_index, - item->args.apply_uniforms.data_size); - break; - - case SGIMGUI_CMD_DRAW: - _sgimgui_snprintf(&str, "%d: sg_draw(base_element=%d, num_elements=%d, num_instances=%d)", - index, - item->args.draw.base_element, - item->args.draw.num_elements, - item->args.draw.num_instances); - break; - - case SGIMGUI_CMD_END_PASS: - _sgimgui_snprintf(&str, "%d: sg_end_pass()", index); - break; - - case SGIMGUI_CMD_COMMIT: - _sgimgui_snprintf(&str, "%d: sg_commit()", index); - break; - - case SGIMGUI_CMD_ALLOC_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.alloc_buffer.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_buffer() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.alloc_image.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_image() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.alloc_sampler.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_sampler() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.alloc_shader.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_shader() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.alloc_pipeline.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_pipeline() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_ALLOC_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.alloc_attachments.result); - _sgimgui_snprintf(&str, "%d: sg_alloc_attachments() => %s", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.dealloc_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_dealloc_buffer(buf=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.dealloc_image.image); - _sgimgui_snprintf(&str, "%d: sg_dealloc_image(img=%d)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.dealloc_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_dealloc_sampler(smp=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.dealloc_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_dealloc_shader(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.dealloc_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_dealloc_pipeline(pip=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_DEALLOC_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.dealloc_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_dealloc_attachments(atts=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.init_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_init_buffer(buf=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.init_image.image); - _sgimgui_snprintf(&str, "%d: sg_init_image(img=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.init_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_init_sampler(smp=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.init_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_init_shader(shd=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.init_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_init_pipeline(pip=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_INIT_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.init_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_init_attachments(atts=%s, desc=..)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.uninit_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_uninit_buffer(buf=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.uninit_image.image); - _sgimgui_snprintf(&str, "%d: sg_uninit_image(img=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.uninit_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_uninit_sampler(smp=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.uninit_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_uninit_shader(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.uninit_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_uninit_pipeline(pip=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_UNINIT_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.uninit_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_uninit_attachments(atts=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_BUFFER: - { - sgimgui_str_t res_id = _sgimgui_buffer_id_string(ctx, item->args.fail_buffer.buffer); - _sgimgui_snprintf(&str, "%d: sg_fail_buffer(buf=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_IMAGE: - { - sgimgui_str_t res_id = _sgimgui_image_id_string(ctx, item->args.fail_image.image); - _sgimgui_snprintf(&str, "%d: sg_fail_image(img=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_SAMPLER: - { - sgimgui_str_t res_id = _sgimgui_sampler_id_string(ctx, item->args.fail_sampler.sampler); - _sgimgui_snprintf(&str, "%d: sg_fail_sampler(smp=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_SHADER: - { - sgimgui_str_t res_id = _sgimgui_shader_id_string(ctx, item->args.fail_shader.shader); - _sgimgui_snprintf(&str, "%d: sg_fail_shader(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_PIPELINE: - { - sgimgui_str_t res_id = _sgimgui_pipeline_id_string(ctx, item->args.fail_pipeline.pipeline); - _sgimgui_snprintf(&str, "%d: sg_fail_pipeline(shd=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_FAIL_ATTACHMENTS: - { - sgimgui_str_t res_id = _sgimgui_attachments_id_string(ctx, item->args.fail_attachments.attachments); - _sgimgui_snprintf(&str, "%d: sg_fail_attachments(atts=%s)", index, res_id.buf); - } - break; - - case SGIMGUI_CMD_PUSH_DEBUG_GROUP: - _sgimgui_snprintf(&str, "%d: sg_push_debug_group(name=%s)", index, - item->args.push_debug_group.name.buf); - break; - - case SGIMGUI_CMD_POP_DEBUG_GROUP: - _sgimgui_snprintf(&str, "%d: sg_pop_debug_group()", index); - break; - - default: - _sgimgui_snprintf(&str, "%d: ???", index); - break; - } - return str; -} - -/*--- CAPTURE CALLBACKS ------------------------------------------------------*/ -_SOKOL_PRIVATE void _sgimgui_reset_state_cache(void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_RESET_STATE_CACHE; - item->color = _SGIMGUI_COLOR_OTHER; - } - if (ctx->hooks.reset_state_cache) { - ctx->hooks.reset_state_cache(ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_buffer(const sg_buffer_desc* desc, sg_buffer buf_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_buffer.result = buf_id; - } - if (ctx->hooks.make_buffer) { - ctx->hooks.make_buffer(desc, buf_id, ctx->hooks.user_data); - } - if (buf_id.id != SG_INVALID_ID) { - _sgimgui_buffer_created(ctx, buf_id, _sgimgui_slot_index(buf_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_image(const sg_image_desc* desc, sg_image img_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_image.result = img_id; - } - if (ctx->hooks.make_image) { - ctx->hooks.make_image(desc, img_id, ctx->hooks.user_data); - } - if (img_id.id != SG_INVALID_ID) { - _sgimgui_image_created(ctx, img_id, _sgimgui_slot_index(img_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_sampler(const sg_sampler_desc* desc, sg_sampler smp_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_sampler.result = smp_id; - } - if (ctx->hooks.make_sampler) { - ctx->hooks.make_sampler(desc, smp_id, ctx->hooks.user_data); - } - if (smp_id.id != SG_INVALID_ID) { - _sgimgui_sampler_created(ctx, smp_id, _sgimgui_slot_index(smp_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_shader(const sg_shader_desc* desc, sg_shader shd_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_shader.result = shd_id; - } - if (ctx->hooks.make_shader) { - ctx->hooks.make_shader(desc, shd_id, ctx->hooks.user_data); - } - if (shd_id.id != SG_INVALID_ID) { - _sgimgui_shader_created(ctx, shd_id, _sgimgui_slot_index(shd_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_pipeline(const sg_pipeline_desc* desc, sg_pipeline pip_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_pipeline.result = pip_id; - } - if (ctx->hooks.make_pipeline) { - ctx->hooks.make_pipeline(desc, pip_id, ctx->hooks.user_data); - } - if (pip_id.id != SG_INVALID_ID) { - _sgimgui_pipeline_created(ctx, pip_id, _sgimgui_slot_index(pip_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_make_attachments(const sg_attachments_desc* desc, sg_attachments atts_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_MAKE_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.make_attachments.result = atts_id; - } - if (ctx->hooks.make_attachments) { - ctx->hooks.make_attachments(desc, atts_id, ctx->hooks.user_data); - } - if (atts_id.id != SG_INVALID_ID) { - _sgimgui_attachments_created(ctx, atts_id, _sgimgui_slot_index(atts_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_buffer(sg_buffer buf, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_buffer.buffer = buf; - } - if (ctx->hooks.destroy_buffer) { - ctx->hooks.destroy_buffer(buf, ctx->hooks.user_data); - } - if (buf.id != SG_INVALID_ID) { - _sgimgui_buffer_destroyed(ctx, _sgimgui_slot_index(buf.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_image(sg_image img, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_image.image = img; - } - if (ctx->hooks.destroy_image) { - ctx->hooks.destroy_image(img, ctx->hooks.user_data); - } - if (img.id != SG_INVALID_ID) { - _sgimgui_image_destroyed(ctx, _sgimgui_slot_index(img.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_sampler(sg_sampler smp, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_sampler.sampler = smp; - } - if (ctx->hooks.destroy_sampler) { - ctx->hooks.destroy_sampler(smp, ctx->hooks.user_data); - } - if (smp.id != SG_INVALID_ID) { - _sgimgui_sampler_destroyed(ctx, _sgimgui_slot_index(smp.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_shader(sg_shader shd, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_shader.shader = shd; - } - if (ctx->hooks.destroy_shader) { - ctx->hooks.destroy_shader(shd, ctx->hooks.user_data); - } - if (shd.id != SG_INVALID_ID) { - _sgimgui_shader_destroyed(ctx, _sgimgui_slot_index(shd.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_pipeline(sg_pipeline pip, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_pipeline.pipeline = pip; - } - if (ctx->hooks.destroy_pipeline) { - ctx->hooks.destroy_pipeline(pip, ctx->hooks.user_data); - } - if (pip.id != SG_INVALID_ID) { - _sgimgui_pipeline_destroyed(ctx, _sgimgui_slot_index(pip.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_destroy_attachments(sg_attachments atts, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DESTROY_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.destroy_attachments.attachments = atts; - } - if (ctx->hooks.destroy_attachments) { - ctx->hooks.destroy_attachments(atts, ctx->hooks.user_data); - } - if (atts.id != SG_INVALID_ID) { - _sgimgui_attachments_destroyed(ctx, _sgimgui_slot_index(atts.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_update_buffer(sg_buffer buf, const sg_range* data, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UPDATE_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.update_buffer.buffer = buf; - item->args.update_buffer.data_size = data->size; - } - if (ctx->hooks.update_buffer) { - ctx->hooks.update_buffer(buf, data, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_update_image(sg_image img, const sg_image_data* data, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UPDATE_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.update_image.image = img; - } - if (ctx->hooks.update_image) { - ctx->hooks.update_image(img, data, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_append_buffer(sg_buffer buf, const sg_range* data, int result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPEND_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.append_buffer.buffer = buf; - item->args.append_buffer.data_size = data->size; - item->args.append_buffer.result = result; - } - if (ctx->hooks.append_buffer) { - ctx->hooks.append_buffer(buf, data, result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_begin_pass(const sg_pass* pass, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - SOKOL_ASSERT(pass); - item->cmd = SGIMGUI_CMD_BEGIN_PASS; - item->color = _SGIMGUI_COLOR_PASS; - item->args.begin_pass.pass = *pass; - } - if (ctx->hooks.begin_pass) { - ctx->hooks.begin_pass(pass, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_viewport(int x, int y, int width, int height, bool origin_top_left, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPLY_VIEWPORT; - item->color = _SGIMGUI_COLOR_APPLY; - item->args.apply_viewport.x = x; - item->args.apply_viewport.y = y; - item->args.apply_viewport.width = width; - item->args.apply_viewport.height = height; - item->args.apply_viewport.origin_top_left = origin_top_left; - } - if (ctx->hooks.apply_viewport) { - ctx->hooks.apply_viewport(x, y, width, height, origin_top_left, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPLY_SCISSOR_RECT; - item->color = _SGIMGUI_COLOR_APPLY; - item->args.apply_scissor_rect.x = x; - item->args.apply_scissor_rect.y = y; - item->args.apply_scissor_rect.width = width; - item->args.apply_scissor_rect.height = height; - item->args.apply_scissor_rect.origin_top_left = origin_top_left; - } - if (ctx->hooks.apply_scissor_rect) { - ctx->hooks.apply_scissor_rect(x, y, width, height, origin_top_left, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_pipeline(sg_pipeline pip, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - ctx->cur_pipeline = pip; /* stored for _sgimgui_apply_uniforms */ - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPLY_PIPELINE; - item->color = _SGIMGUI_COLOR_APPLY; - item->args.apply_pipeline.pipeline = pip; - } - if (ctx->hooks.apply_pipeline) { - ctx->hooks.apply_pipeline(pip, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_bindings(const sg_bindings* bindings, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - SOKOL_ASSERT(bindings); - item->cmd = SGIMGUI_CMD_APPLY_BINDINGS; - item->color = _SGIMGUI_COLOR_APPLY; - item->args.apply_bindings.bindings = *bindings; - } - if (ctx->hooks.apply_bindings) { - ctx->hooks.apply_bindings(bindings, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - SOKOL_ASSERT(data); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_APPLY_UNIFORMS; - item->color = _SGIMGUI_COLOR_APPLY; - sgimgui_args_apply_uniforms_t* args = &item->args.apply_uniforms; - args->stage = stage; - args->ub_index = ub_index; - args->data_size = data->size; - args->pipeline = ctx->cur_pipeline; - args->ubuf_pos = _sgimgui_capture_uniforms(ctx, data); - } - if (ctx->hooks.apply_uniforms) { - ctx->hooks.apply_uniforms(stage, ub_index, data, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw(int base_element, int num_elements, int num_instances, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DRAW; - item->color = _SGIMGUI_COLOR_DRAW; - item->args.draw.base_element = base_element; - item->args.draw.num_elements = num_elements; - item->args.draw.num_instances = num_instances; - } - if (ctx->hooks.draw) { - ctx->hooks.draw(base_element, num_elements, num_instances, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_end_pass(void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - ctx->cur_pipeline.id = SG_INVALID_ID; - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_END_PASS; - item->color = _SGIMGUI_COLOR_PASS; - } - if (ctx->hooks.end_pass) { - ctx->hooks.end_pass(ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_commit(void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_COMMIT; - item->color = _SGIMGUI_COLOR_OTHER; - } - _sgimgui_capture_next_frame(ctx); - if (ctx->hooks.commit) { - ctx->hooks.commit(ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_buffer(sg_buffer result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_buffer.result = result; - } - if (ctx->hooks.alloc_buffer) { - ctx->hooks.alloc_buffer(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_image(sg_image result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_image.result = result; - } - if (ctx->hooks.alloc_image) { - ctx->hooks.alloc_image(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_sampler(sg_sampler result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_sampler.result = result; - } - if (ctx->hooks.alloc_sampler) { - ctx->hooks.alloc_sampler(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_shader(sg_shader result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_shader.result = result; - } - if (ctx->hooks.alloc_shader) { - ctx->hooks.alloc_shader(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_pipeline(sg_pipeline result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_pipeline.result = result; - } - if (ctx->hooks.alloc_pipeline) { - ctx->hooks.alloc_pipeline(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_alloc_attachments(sg_attachments result, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_ALLOC_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.alloc_attachments.result = result; - } - if (ctx->hooks.alloc_attachments) { - ctx->hooks.alloc_attachments(result, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_buffer(sg_buffer buf_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_buffer.buffer = buf_id; - } - if (ctx->hooks.dealloc_buffer) { - ctx->hooks.dealloc_buffer(buf_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_image(sg_image img_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_image.image = img_id; - } - if (ctx->hooks.dealloc_image) { - ctx->hooks.dealloc_image(img_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_sampler(sg_sampler smp_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_sampler.sampler = smp_id; - } - if (ctx->hooks.dealloc_sampler) { - ctx->hooks.dealloc_sampler(smp_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_shader(sg_shader shd_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_shader.shader = shd_id; - } - if (ctx->hooks.dealloc_shader) { - ctx->hooks.dealloc_shader(shd_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_pipeline(sg_pipeline pip_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_pipeline.pipeline = pip_id; - } - if (ctx->hooks.dealloc_pipeline) { - ctx->hooks.dealloc_pipeline(pip_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_dealloc_attachments(sg_attachments atts_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_DEALLOC_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.dealloc_attachments.attachments = atts_id; - } - if (ctx->hooks.dealloc_attachments) { - ctx->hooks.dealloc_attachments(atts_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_buffer.buffer = buf_id; - } - if (ctx->hooks.init_buffer) { - ctx->hooks.init_buffer(buf_id, desc, ctx->hooks.user_data); - } - if (buf_id.id != SG_INVALID_ID) { - _sgimgui_buffer_created(ctx, buf_id, _sgimgui_slot_index(buf_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_image(sg_image img_id, const sg_image_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_image.image = img_id; - } - if (ctx->hooks.init_image) { - ctx->hooks.init_image(img_id, desc, ctx->hooks.user_data); - } - if (img_id.id != SG_INVALID_ID) { - _sgimgui_image_created(ctx, img_id, _sgimgui_slot_index(img_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_sampler(sg_sampler smp_id, const sg_sampler_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_sampler.sampler = smp_id; - } - if (ctx->hooks.init_sampler) { - ctx->hooks.init_sampler(smp_id, desc, ctx->hooks.user_data); - } - if (smp_id.id != SG_INVALID_ID) { - _sgimgui_sampler_created(ctx, smp_id, _sgimgui_slot_index(smp_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_shader(sg_shader shd_id, const sg_shader_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_shader.shader = shd_id; - } - if (ctx->hooks.init_shader) { - ctx->hooks.init_shader(shd_id, desc, ctx->hooks.user_data); - } - if (shd_id.id != SG_INVALID_ID) { - _sgimgui_shader_created(ctx, shd_id, _sgimgui_slot_index(shd_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_pipeline.pipeline = pip_id; - } - if (ctx->hooks.init_pipeline) { - ctx->hooks.init_pipeline(pip_id, desc, ctx->hooks.user_data); - } - if (pip_id.id != SG_INVALID_ID) { - _sgimgui_pipeline_created(ctx, pip_id, _sgimgui_slot_index(pip_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_init_attachments(sg_attachments atts_id, const sg_attachments_desc* desc, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_INIT_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.init_attachments.attachments = atts_id; - } - if (ctx->hooks.init_attachments) { - ctx->hooks.init_attachments(atts_id, desc, ctx->hooks.user_data); - } - if (atts_id.id != SG_INVALID_ID) { - _sgimgui_attachments_created(ctx, atts_id, _sgimgui_slot_index(atts_id.id), desc); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_buffer(sg_buffer buf, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_buffer.buffer = buf; - } - if (ctx->hooks.uninit_buffer) { - ctx->hooks.uninit_buffer(buf, ctx->hooks.user_data); - } - if (buf.id != SG_INVALID_ID) { - _sgimgui_buffer_destroyed(ctx, _sgimgui_slot_index(buf.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_image(sg_image img, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_image.image = img; - } - if (ctx->hooks.uninit_image) { - ctx->hooks.uninit_image(img, ctx->hooks.user_data); - } - if (img.id != SG_INVALID_ID) { - _sgimgui_image_destroyed(ctx, _sgimgui_slot_index(img.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_sampler(sg_sampler smp, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_sampler.sampler = smp; - } - if (ctx->hooks.uninit_sampler) { - ctx->hooks.uninit_sampler(smp, ctx->hooks.user_data); - } - if (smp.id != SG_INVALID_ID) { - _sgimgui_sampler_destroyed(ctx, _sgimgui_slot_index(smp.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_shader(sg_shader shd, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_shader.shader = shd; - } - if (ctx->hooks.uninit_shader) { - ctx->hooks.uninit_shader(shd, ctx->hooks.user_data); - } - if (shd.id != SG_INVALID_ID) { - _sgimgui_shader_destroyed(ctx, _sgimgui_slot_index(shd.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_pipeline(sg_pipeline pip, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_pipeline.pipeline = pip; - } - if (ctx->hooks.uninit_pipeline) { - ctx->hooks.uninit_pipeline(pip, ctx->hooks.user_data); - } - if (pip.id != SG_INVALID_ID) { - _sgimgui_pipeline_destroyed(ctx, _sgimgui_slot_index(pip.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_uninit_attachments(sg_attachments atts, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_UNINIT_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.uninit_attachments.attachments = atts; - } - if (ctx->hooks.uninit_attachments) { - ctx->hooks.uninit_attachments(atts, ctx->hooks.user_data); - } - if (atts.id != SG_INVALID_ID) { - _sgimgui_attachments_destroyed(ctx, _sgimgui_slot_index(atts.id)); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_buffer(sg_buffer buf_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_BUFFER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_buffer.buffer = buf_id; - } - if (ctx->hooks.fail_buffer) { - ctx->hooks.fail_buffer(buf_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_image(sg_image img_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_IMAGE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_image.image = img_id; - } - if (ctx->hooks.fail_image) { - ctx->hooks.fail_image(img_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_sampler(sg_sampler smp_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_SAMPLER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_sampler.sampler = smp_id; - } - if (ctx->hooks.fail_sampler) { - ctx->hooks.fail_sampler(smp_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_shader(sg_shader shd_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_SHADER; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_shader.shader = shd_id; - } - if (ctx->hooks.fail_shader) { - ctx->hooks.fail_shader(shd_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_pipeline(sg_pipeline pip_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_PIPELINE; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_pipeline.pipeline = pip_id; - } - if (ctx->hooks.fail_pipeline) { - ctx->hooks.fail_pipeline(pip_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_fail_attachments(sg_attachments atts_id, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_FAIL_ATTACHMENTS; - item->color = _SGIMGUI_COLOR_RSRC; - item->args.fail_attachments.attachments = atts_id; - } - if (ctx->hooks.fail_attachments) { - ctx->hooks.fail_attachments(atts_id, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_push_debug_group(const char* name, void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - if (0 == strcmp(name, "sokol-imgui")) { - ctx->frame_stats_window.in_sokol_imgui = true; - if (ctx->frame_stats_window.disable_sokol_imgui_stats) { - sg_disable_frame_stats(); - } - } - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_PUSH_DEBUG_GROUP; - item->color = _SGIMGUI_COLOR_OTHER; - item->args.push_debug_group.name = _sgimgui_make_str(name); - } - if (ctx->hooks.push_debug_group) { - ctx->hooks.push_debug_group(name, ctx->hooks.user_data); - } -} - -_SOKOL_PRIVATE void _sgimgui_pop_debug_group(void* user_data) { - sgimgui_t* ctx = (sgimgui_t*) user_data; - SOKOL_ASSERT(ctx); - if (ctx->frame_stats_window.in_sokol_imgui) { - ctx->frame_stats_window.in_sokol_imgui = false; - if (ctx->frame_stats_window.disable_sokol_imgui_stats) { - sg_enable_frame_stats(); - } - } - sgimgui_capture_item_t* item = _sgimgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SGIMGUI_CMD_POP_DEBUG_GROUP; - item->color = _SGIMGUI_COLOR_OTHER; - } - if (ctx->hooks.pop_debug_group) { - ctx->hooks.pop_debug_group(ctx->hooks.user_data); - } -} - -/*--- IMGUI HELPERS ----------------------------------------------------------*/ -_SOKOL_PRIVATE bool _sgimgui_draw_resid_list_item(uint32_t res_id, const char* label, bool selected) { - igPushID_Int((int)res_id); - bool res; - if (label[0]) { - res = igSelectable_Bool(label, selected, 0, IMVEC2(0,0)); - } else { - sgimgui_str_t str; - _sgimgui_snprintf(&str, "0x%08X", res_id); - res = igSelectable_Bool(str.buf, selected, 0, IMVEC2(0,0)); - } - igPopID(); - return res; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_resid_link(uint32_t res_type, uint32_t res_id, const char* label) { - SOKOL_ASSERT(label); - sgimgui_str_t str_buf; - const char* str; - if (label[0]) { - str = label; - } else { - _sgimgui_snprintf(&str_buf, "0x%08X", res_id); - str = str_buf.buf; - } - igPushID_Int((int)((res_type<<24)|res_id)); - bool res = igSmallButton(str); - igPopID(); - return res; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_buffer_link(sgimgui_t* ctx, sg_buffer buf) { - bool retval = false; - if (buf.id != SG_INVALID_ID) { - const sgimgui_buffer_t* buf_ui = &ctx->buffer_window.slots[_sgimgui_slot_index(buf.id)]; - retval = _sgimgui_draw_resid_link(1, buf.id, buf_ui->label.buf); - } - return retval; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_image_link(sgimgui_t* ctx, sg_image img) { - bool retval = false; - if (img.id != SG_INVALID_ID) { - const sgimgui_image_t* img_ui = &ctx->image_window.slots[_sgimgui_slot_index(img.id)]; - retval = _sgimgui_draw_resid_link(2, img.id, img_ui->label.buf); - } - return retval; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_sampler_link(sgimgui_t* ctx, sg_sampler smp) { - bool retval = false; - if (smp.id != SG_INVALID_ID) { - const sgimgui_sampler_t* smp_ui = &ctx->sampler_window.slots[_sgimgui_slot_index(smp.id)]; - retval = _sgimgui_draw_resid_link(2, smp.id, smp_ui->label.buf); - } - return retval; -} - -_SOKOL_PRIVATE bool _sgimgui_draw_shader_link(sgimgui_t* ctx, sg_shader shd) { - bool retval = false; - if (shd.id != SG_INVALID_ID) { - const sgimgui_shader_t* shd_ui = &ctx->shader_window.slots[_sgimgui_slot_index(shd.id)]; - retval = _sgimgui_draw_resid_link(3, shd.id, shd_ui->label.buf); - } - return retval; -} - -_SOKOL_PRIVATE void _sgimgui_show_buffer(sgimgui_t* ctx, sg_buffer buf) { - ctx->buffer_window.open = true; - ctx->buffer_window.sel_buf = buf; -} - -_SOKOL_PRIVATE void _sgimgui_show_image(sgimgui_t* ctx, sg_image img) { - ctx->image_window.open = true; - ctx->image_window.sel_img = img; -} - -_SOKOL_PRIVATE void _sgimgui_show_sampler(sgimgui_t* ctx, sg_sampler smp) { - ctx->sampler_window.open = true; - ctx->sampler_window.sel_smp = smp; -} - -_SOKOL_PRIVATE void _sgimgui_show_shader(sgimgui_t* ctx, sg_shader shd) { - ctx->shader_window.open = true; - ctx->shader_window.sel_shd = shd; -} - -_SOKOL_PRIVATE void _sgimgui_draw_buffer_list(sgimgui_t* ctx) { - igBeginChild_Str("buffer_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 0; i < ctx->buffer_window.num_slots; i++) { - sg_buffer buf = ctx->buffer_window.slots[i].res_id; - sg_resource_state state = sg_query_buffer_state(buf); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->buffer_window.sel_buf.id == buf.id; - if (_sgimgui_draw_resid_list_item(buf.id, ctx->buffer_window.slots[i].label.buf, selected)) { - ctx->buffer_window.sel_buf.id = buf.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_image_list(sgimgui_t* ctx) { - igBeginChild_Str("image_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 0; i < ctx->image_window.num_slots; i++) { - sg_image img = ctx->image_window.slots[i].res_id; - sg_resource_state state = sg_query_image_state(img); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->image_window.sel_img.id == img.id; - if (_sgimgui_draw_resid_list_item(img.id, ctx->image_window.slots[i].label.buf, selected)) { - ctx->image_window.sel_img.id = img.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_sampler_list(sgimgui_t* ctx) { - igBeginChild_Str("sampler_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 0; i < ctx->sampler_window.num_slots; i++) { - sg_sampler smp = ctx->sampler_window.slots[i].res_id; - sg_resource_state state = sg_query_sampler_state(smp); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->sampler_window.sel_smp.id == smp.id; - if (_sgimgui_draw_resid_list_item(smp.id, ctx->sampler_window.slots[i].label.buf, selected)) { - ctx->sampler_window.sel_smp.id = smp.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_shader_list(sgimgui_t* ctx) { - igBeginChild_Str("shader_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 0; i < ctx->shader_window.num_slots; i++) { - sg_shader shd = ctx->shader_window.slots[i].res_id; - sg_resource_state state = sg_query_shader_state(shd); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->shader_window.sel_shd.id == shd.id; - if (_sgimgui_draw_resid_list_item(shd.id, ctx->shader_window.slots[i].label.buf, selected)) { - ctx->shader_window.sel_shd.id = shd.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_pipeline_list(sgimgui_t* ctx) { - igBeginChild_Str("pipeline_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 1; i < ctx->pipeline_window.num_slots; i++) { - sg_pipeline pip = ctx->pipeline_window.slots[i].res_id; - sg_resource_state state = sg_query_pipeline_state(pip); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->pipeline_window.sel_pip.id == pip.id; - if (_sgimgui_draw_resid_list_item(pip.id, ctx->pipeline_window.slots[i].label.buf, selected)) { - ctx->pipeline_window.sel_pip.id = pip.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_attachments_list(sgimgui_t* ctx) { - igBeginChild_Str("pass_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - for (int i = 1; i < ctx->attachments_window.num_slots; i++) { - sg_attachments atts = ctx->attachments_window.slots[i].res_id; - sg_resource_state state = sg_query_attachments_state(atts); - if ((state != SG_RESOURCESTATE_INVALID) && (state != SG_RESOURCESTATE_INITIAL)) { - bool selected = ctx->attachments_window.sel_atts.id == atts.id; - if (_sgimgui_draw_resid_list_item(atts.id, ctx->attachments_window.slots[i].label.buf, selected)) { - ctx->attachments_window.sel_atts.id = atts.id; - } - } - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_capture_list(sgimgui_t* ctx) { - igBeginChild_Str("capture_list", IMVEC2(_SGIMGUI_LIST_WIDTH,0), true, 0); - const int num_items = _sgimgui_capture_num_read_items(ctx); - uint64_t group_stack = 1; /* bit set: group unfolded, cleared: folded */ - for (int i = 0; i < num_items; i++) { - const sgimgui_capture_item_t* item = _sgimgui_capture_read_item_at(ctx, i); - sgimgui_str_t item_string = _sgimgui_capture_item_string(ctx, i, item); - igPushStyleColor_U32(ImGuiCol_Text, item->color); - igPushID_Int(i); - if (item->cmd == SGIMGUI_CMD_PUSH_DEBUG_GROUP) { - if (group_stack & 1) { - group_stack <<= 1; - const char* group_name = item->args.push_debug_group.name.buf; - if (igTreeNode_StrStr(group_name, "Group: %s", group_name)) { - group_stack |= 1; - } - } else { - group_stack <<= 1; - } - } else if (item->cmd == SGIMGUI_CMD_POP_DEBUG_GROUP) { - if (group_stack & 1) { - igTreePop(); - } - group_stack >>= 1; - } else if (group_stack & 1) { - if (igSelectable_Bool(item_string.buf, ctx->capture_window.sel_item == i, 0, IMVEC2(0,0))) { - ctx->capture_window.sel_item = i; - } - if (igIsItemHovered(0)) { - igSetTooltip("%s", item_string.buf); - } - } - igPopID(); - igPopStyleColor(1); - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_buffer_panel(sgimgui_t* ctx, sg_buffer buf) { - if (buf.id != SG_INVALID_ID) { - igBeginChild_Str("buffer", IMVEC2(0,0), false, 0); - sg_buffer_info info = sg_query_buffer_info(buf); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - const sgimgui_buffer_t* buf_ui = &ctx->buffer_window.slots[_sgimgui_slot_index(buf.id)]; - igText("Label: %s", buf_ui->label.buf[0] ? buf_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - igText("Type: %s", _sgimgui_buffertype_string(buf_ui->desc.type)); - igText("Usage: %s", _sgimgui_usage_string(buf_ui->desc.usage)); - igText("Size: %d", buf_ui->desc.size); - if (buf_ui->desc.usage != SG_USAGE_IMMUTABLE) { - igSeparator(); - igText("Num Slots: %d", info.num_slots); - igText("Active Slot: %d", info.active_slot); - igText("Update Frame Index: %d", info.update_frame_index); - igText("Append Frame Index: %d", info.append_frame_index); - igText("Append Pos: %d", info.append_pos); - igText("Append Overflow: %s", _sgimgui_bool_string(info.append_overflow)); - } - } else { - igText("Buffer 0x%08X not valid.", buf.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE bool _sgimgui_image_renderable(sg_image_type type, sg_pixel_format fmt, int sample_count) { - return (type == SG_IMAGETYPE_2D) - && sg_query_pixelformat(fmt).sample - && sample_count == 1; -} - -_SOKOL_PRIVATE void _sgimgui_draw_embedded_image(sgimgui_t* ctx, sg_image img, float* scale) { - if (sg_query_image_state(img) == SG_RESOURCESTATE_VALID) { - sgimgui_image_t* img_ui = &ctx->image_window.slots[_sgimgui_slot_index(img.id)]; - if (_sgimgui_image_renderable(img_ui->desc.type, img_ui->desc.pixel_format, img_ui->desc.sample_count)) { - igPushID_Int((int)img.id); - igSliderFloat("Scale", scale, 0.125f, 8.0f, "%.3f", ImGuiSliderFlags_Logarithmic); - float w = (float)img_ui->desc.width * (*scale); - float h = (float)img_ui->desc.height * (*scale); - igImage(simgui_imtextureid(img_ui->simgui_img), IMVEC2(w, h), IMVEC2(0,0), IMVEC2(1,1), IMVEC4(1,1,1,1), IMVEC4(0,0,0,0)); - igPopID(); - } else { - igText("Image not renderable."); - } - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_image_panel(sgimgui_t* ctx, sg_image img) { - if (img.id != SG_INVALID_ID) { - igBeginChild_Str("image", IMVEC2(0,0), false, 0); - sg_image_info info = sg_query_image_info(img); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - sgimgui_image_t* img_ui = &ctx->image_window.slots[_sgimgui_slot_index(img.id)]; - const sg_image_desc* desc = &img_ui->desc; - igText("Label: %s", img_ui->label.buf[0] ? img_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - _sgimgui_draw_embedded_image(ctx, img, &img_ui->ui_scale); - igSeparator(); - igText("Type: %s", _sgimgui_imagetype_string(desc->type)); - igText("Usage: %s", _sgimgui_usage_string(desc->usage)); - igText("Render Target: %s", _sgimgui_bool_string(desc->render_target)); - igText("Width: %d", desc->width); - igText("Height: %d", desc->height); - igText("Num Slices: %d", desc->num_slices); - igText("Num Mipmaps: %d", desc->num_mipmaps); - igText("Pixel Format: %s", _sgimgui_pixelformat_string(desc->pixel_format)); - igText("Sample Count: %d", desc->sample_count); - if (desc->usage != SG_USAGE_IMMUTABLE) { - igSeparator(); - igText("Num Slots: %d", info.num_slots); - igText("Active Slot: %d", info.active_slot); - igText("Update Frame Index: %d", info.upd_frame_index); - } - } else { - igText("Image 0x%08X not valid.", img.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_sampler_panel(sgimgui_t* ctx, sg_sampler smp) { - if (smp.id != SG_INVALID_ID) { - igBeginChild_Str("sampler", IMVEC2(0,0), false, 0); - sg_sampler_info info = sg_query_sampler_info(smp); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - sgimgui_sampler_t* smp_ui = &ctx->sampler_window.slots[_sgimgui_slot_index(smp.id)]; - const sg_sampler_desc* desc = &smp_ui->desc; - igText("Label: %s", smp_ui->label.buf[0] ? smp_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - igText("Min Filter: %s", _sgimgui_filter_string(desc->min_filter)); - igText("Mag Filter: %s", _sgimgui_filter_string(desc->mag_filter)); - igText("Mipmap Filter: %s", _sgimgui_filter_string(desc->mipmap_filter)); - igText("Wrap U: %s", _sgimgui_wrap_string(desc->wrap_u)); - igText("Wrap V: %s", _sgimgui_wrap_string(desc->wrap_v)); - igText("Wrap W: %s", _sgimgui_wrap_string(desc->wrap_w)); - igText("Min LOD: %.3f", desc->min_lod); - igText("Max LOD: %.3f", desc->max_lod); - igText("Border Color: %s", _sgimgui_bordercolor_string(desc->border_color)); - igText("Compare: %s", _sgimgui_comparefunc_string(desc->compare)); - igText("Max Anisotropy: %d", desc->max_anisotropy); - } else { - igText("Sampler 0x%08X not valid.", smp.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_shader_stage(const sg_shader_stage_desc* stage) { - int num_valid_ubs = 0; - for (int i = 0; i < SG_MAX_SHADERSTAGE_UBS; i++) { - const sg_shader_uniform_block_desc* ub = &stage->uniform_blocks[i]; - for (int j = 0; j < SG_MAX_UB_MEMBERS; j++) { - const sg_shader_uniform_desc* u = &ub->uniforms[j]; - if (SG_UNIFORMTYPE_INVALID != u->type) { - num_valid_ubs++; - break; - } - } - } - int num_valid_images = 0; - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { - if (stage->images[i].used) { - num_valid_images++; - } else { - break; - } - } - int num_valid_samplers = 0; - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++) { - if (stage->samplers[i].used) { - num_valid_samplers++; - } else { - break; - } - } - int num_valid_image_sampler_pairs = 0; - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS; i++) { - if (stage->image_sampler_pairs[i].used) { - num_valid_image_sampler_pairs++; - } else { - break; - } - } - int num_valid_storage_buffers = 0; - for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { - if (stage->storage_buffers[i].used) { - num_valid_storage_buffers++; - } else { - break; - } - } - - if (num_valid_ubs > 0) { - if (igTreeNode_Str("Uniform Blocks")) { - for (int i = 0; i < num_valid_ubs; i++) { - const sg_shader_uniform_block_desc* ub = &stage->uniform_blocks[i]; - igText("#%d: (size: %d layout: %s)\n", i, ub->size, _sgimgui_uniformlayout_string(ub->layout)); - for (int j = 0; j < SG_MAX_UB_MEMBERS; j++) { - const sg_shader_uniform_desc* u = &ub->uniforms[j]; - if (SG_UNIFORMTYPE_INVALID != u->type) { - if (u->array_count <= 1) { - igText(" %s %s", _sgimgui_uniformtype_string(u->type), u->name ? u->name : ""); - } else { - igText(" %s[%d] %s", _sgimgui_uniformtype_string(u->type), u->array_count, u->name ? u->name : ""); - } - } - } - } - igTreePop(); - } - } - if (num_valid_images > 0) { - if (igTreeNode_Str("Images")) { - for (int i = 0; i < num_valid_images; i++) { - const sg_shader_image_desc* sid = &stage->images[i]; - igText("slot: %d\n multisampled: %s\n image_type: %s\n sample_type: %s", - i, - sid->multisampled ? "true" : "false", - _sgimgui_imagetype_string(sid->image_type), - _sgimgui_imagesampletype_string(sid->sample_type)); - } - igTreePop(); - } - } - if (num_valid_samplers > 0) { - if (igTreeNode_Str("Samplers")) { - for (int i = 0; i < num_valid_samplers; i++) { - const sg_shader_sampler_desc* ssd = &stage->samplers[i]; - igText("slot: %d\n sampler_type: %s", i, _sgimgui_samplertype_string(ssd->sampler_type)); - } - igTreePop(); - } - } - if (num_valid_image_sampler_pairs > 0) { - if (igTreeNode_Str("Image Sampler Pairs")) { - for (int i = 0; i < num_valid_image_sampler_pairs; i++) { - const sg_shader_image_sampler_pair_desc* sispd = &stage->image_sampler_pairs[i]; - igText("slot: %d\n image_slot: %d\n sampler_slot: %d\n glsl_name: %s\n", - i, - sispd->image_slot, - sispd->sampler_slot, - sispd->glsl_name ? sispd->glsl_name : "---"); - } - igTreePop(); - } - } - if (num_valid_storage_buffers > 0) { - if (igTreeNode_Str("Storage Buffers")) { - for (int i = 0; i < num_valid_storage_buffers; i++) { - const sg_shader_storage_buffer_desc* sbuf_desc = &stage->storage_buffers[i]; - igText("slot: %d\n readonly: %s\n", i, sbuf_desc->readonly ? "true" : "false"); - } - igTreePop(); - } - } - if (stage->entry) { - igText("Entry: %s", stage->entry); - } - if (stage->d3d11_target) { - igText("D3D11 Target: %s", stage->d3d11_target); - } - if (stage->source) { - if (igTreeNode_Str("Source")) { - igText("%s", stage->source); - igTreePop(); - } - } else if (stage->bytecode.ptr) { - if (igTreeNode_Str("Byte Code")) { - igText("Byte-code display currently not supported."); - igTreePop(); - } - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_shader_panel(sgimgui_t* ctx, sg_shader shd) { - if (shd.id != SG_INVALID_ID) { - igBeginChild_Str("shader", IMVEC2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); - sg_shader_info info = sg_query_shader_info(shd); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - const sgimgui_shader_t* shd_ui = &ctx->shader_window.slots[_sgimgui_slot_index(shd.id)]; - igText("Label: %s", shd_ui->label.buf[0] ? shd_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - if (igTreeNode_Str("Attrs")) { - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - const sg_shader_attr_desc* a_desc = &shd_ui->desc.attrs[i]; - if (a_desc->name || a_desc->sem_index) { - igText("#%d:", i); - igText(" Name: %s", a_desc->name ? a_desc->name : "---"); - igText(" Sem Name: %s", a_desc->sem_name ? a_desc->sem_name : "---"); - igText(" Sem Index: %d", a_desc->sem_index); - } - } - igTreePop(); - } - if (igTreeNode_Str("Vertex Shader Stage")) { - _sgimgui_draw_shader_stage(&shd_ui->desc.vs); - igTreePop(); - } - if (igTreeNode_Str("Fragment Shader Stage")) { - _sgimgui_draw_shader_stage(&shd_ui->desc.fs); - igTreePop(); - } - } else { - igText("Shader 0x%08X not valid!", shd.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_vertex_layout_state(const sg_vertex_layout_state* layout) { - if (igTreeNode_Str("Buffers")) { - for (int i = 0; i < SG_MAX_VERTEX_BUFFERS; i++) { - const sg_vertex_buffer_layout_state* l_state = &layout->buffers[i]; - if (l_state->stride > 0) { - igText("#%d:", i); - igText(" Stride: %d", l_state->stride); - igText(" Step Func: %s", _sgimgui_vertexstep_string(l_state->step_func)); - igText(" Step Rate: %d", l_state->step_rate); - } - } - igTreePop(); - } - if (igTreeNode_Str("Attrs")) { - for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { - const sg_vertex_attr_state* a_state = &layout->attrs[i]; - if (a_state->format != SG_VERTEXFORMAT_INVALID) { - igText("#%d:", i); - igText(" Format: %s", _sgimgui_vertexformat_string(a_state->format)); - igText(" Offset: %d", a_state->offset); - igText(" Buffer Index: %d", a_state->buffer_index); - } - } - igTreePop(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_stencil_face_state(const sg_stencil_face_state* sfs) { - igText("Fail Op: %s", _sgimgui_stencilop_string(sfs->fail_op)); - igText("Depth Fail Op: %s", _sgimgui_stencilop_string(sfs->depth_fail_op)); - igText("Pass Op: %s", _sgimgui_stencilop_string(sfs->pass_op)); - igText("Compare: %s", _sgimgui_comparefunc_string(sfs->compare)); -} - -_SOKOL_PRIVATE void _sgimgui_draw_stencil_state(const sg_stencil_state* ss) { - igText("Enabled: %s", _sgimgui_bool_string(ss->enabled)); - igText("Read Mask: 0x%02X", ss->read_mask); - igText("Write Mask: 0x%02X", ss->write_mask); - igText("Ref: 0x%02X", ss->ref); - if (igTreeNode_Str("Front")) { - _sgimgui_draw_stencil_face_state(&ss->front); - igTreePop(); - } - if (igTreeNode_Str("Back")) { - _sgimgui_draw_stencil_face_state(&ss->back); - igTreePop(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_depth_state(const sg_depth_state* ds) { - igText("Pixel Format: %s", _sgimgui_pixelformat_string(ds->pixel_format)); - igText("Compare: %s", _sgimgui_comparefunc_string(ds->compare)); - igText("Write Enabled: %s", _sgimgui_bool_string(ds->write_enabled)); - igText("Bias: %f", ds->bias); - igText("Bias Slope: %f", ds->bias_slope_scale); - igText("Bias Clamp: %f", ds->bias_clamp); -} - -_SOKOL_PRIVATE void _sgimgui_draw_blend_state(const sg_blend_state* bs) { - igText("Blend Enabled: %s", _sgimgui_bool_string(bs->enabled)); - igText("Src Factor RGB: %s", _sgimgui_blendfactor_string(bs->src_factor_rgb)); - igText("Dst Factor RGB: %s", _sgimgui_blendfactor_string(bs->dst_factor_rgb)); - igText("Op RGB: %s", _sgimgui_blendop_string(bs->op_rgb)); - igText("Src Factor Alpha: %s", _sgimgui_blendfactor_string(bs->src_factor_alpha)); - igText("Dst Factor Alpha: %s", _sgimgui_blendfactor_string(bs->dst_factor_alpha)); - igText("Op Alpha: %s", _sgimgui_blendop_string(bs->op_alpha)); -} - -_SOKOL_PRIVATE void _sgimgui_draw_color_target_state(const sg_color_target_state* cs) { - igText("Pixel Format: %s", _sgimgui_pixelformat_string(cs->pixel_format)); - igText("Write Mask: %s", _sgimgui_colormask_string(cs->write_mask)); - if (igTreeNode_Str("Blend State:")) { - _sgimgui_draw_blend_state(&cs->blend); - igTreePop(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_pipeline_panel(sgimgui_t* ctx, sg_pipeline pip) { - if (pip.id != SG_INVALID_ID) { - igBeginChild_Str("pipeline", IMVEC2(0,0), false, 0); - sg_pipeline_info info = sg_query_pipeline_info(pip); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - const sgimgui_pipeline_t* pip_ui = &ctx->pipeline_window.slots[_sgimgui_slot_index(pip.id)]; - igText("Label: %s", pip_ui->label.buf[0] ? pip_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - igSeparator(); - igText("Shader: "); igSameLine(0,-1); - if (_sgimgui_draw_shader_link(ctx, pip_ui->desc.shader)) { - _sgimgui_show_shader(ctx, pip_ui->desc.shader); - } - if (igTreeNode_Str("Vertex Layout State")) { - _sgimgui_draw_vertex_layout_state(&pip_ui->desc.layout); - igTreePop(); - } - if (igTreeNode_Str("Depth State")) { - _sgimgui_draw_depth_state(&pip_ui->desc.depth); - igTreePop(); - } - if (igTreeNode_Str("Stencil State")) { - _sgimgui_draw_stencil_state(&pip_ui->desc.stencil); - igTreePop(); - } - igText("Color Count: %d", pip_ui->desc.color_count); - for (int i = 0; i < pip_ui->desc.color_count; i++) { - sgimgui_str_t str; - _sgimgui_snprintf(&str, "Color Target %d", i); - if (igTreeNode_Str(str.buf)) { - _sgimgui_draw_color_target_state(&pip_ui->desc.colors[i]); - igTreePop(); - } - } - igText("Prim Type: %s", _sgimgui_primitivetype_string(pip_ui->desc.primitive_type)); - igText("Index Type: %s", _sgimgui_indextype_string(pip_ui->desc.index_type)); - igText("Cull Mode: %s", _sgimgui_cullmode_string(pip_ui->desc.cull_mode)); - igText("Face Winding: %s", _sgimgui_facewinding_string(pip_ui->desc.face_winding)); - igText("Sample Count: %d", pip_ui->desc.sample_count); - sgimgui_str_t blend_color_str; - igText("Blend Color: %.3f %.3f %.3f %.3f", _sgimgui_color_string(&blend_color_str, pip_ui->desc.blend_color)); - igText("Alpha To Coverage: %s", _sgimgui_bool_string(pip_ui->desc.alpha_to_coverage_enabled)); - } else { - igText("Pipeline 0x%08X not valid.", pip.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_attachment(sgimgui_t* ctx, const sg_attachment_desc* att, float* img_scale) { - igText(" Image: "); igSameLine(0,-1); - if (_sgimgui_draw_image_link(ctx, att->image)) { - _sgimgui_show_image(ctx, att->image); - } - igText(" Mip Level: %d", att->mip_level); - igText(" Slice: %d", att->slice); - _sgimgui_draw_embedded_image(ctx, att->image, img_scale); -} - -_SOKOL_PRIVATE void _sgimgui_draw_attachments_panel(sgimgui_t* ctx, sg_attachments atts) { - if (atts.id != SG_INVALID_ID) { - igBeginChild_Str("attachments", IMVEC2(0,0), false, 0); - sg_attachments_info info = sg_query_attachments_info(atts); - if (info.slot.state == SG_RESOURCESTATE_VALID) { - sgimgui_attachments_t* atts_ui = &ctx->attachments_window.slots[_sgimgui_slot_index(atts.id)]; - igText("Label: %s", atts_ui->label.buf[0] ? atts_ui->label.buf : "---"); - _sgimgui_draw_resource_slot(&info.slot); - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (atts_ui->desc.colors[i].image.id == SG_INVALID_ID) { - break; - } - igSeparator(); - igText("Color Image #%d:", i); - _sgimgui_draw_attachment(ctx, &atts_ui->desc.colors[i], &atts_ui->color_image_scale[i]); - } - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (atts_ui->desc.resolves[i].image.id == SG_INVALID_ID) { - break; - } - igSeparator(); - igText("Resolve Image #%d:", i); - _sgimgui_draw_attachment(ctx, &atts_ui->desc.resolves[i], &atts_ui->resolve_image_scale[i]); - } - if (atts_ui->desc.depth_stencil.image.id != SG_INVALID_ID) { - igSeparator(); - igText("Depth-Stencil Image:"); - _sgimgui_draw_attachment(ctx, &atts_ui->desc.depth_stencil, &atts_ui->ds_image_scale); - } - } else { - igText("Attachments 0x%08X not valid.", atts.id); - } - igEndChild(); - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_bindings_panel(sgimgui_t* ctx, const sg_bindings* bnd) { - for (int i = 0; i < SG_MAX_VERTEX_BUFFERS; i++) { - sg_buffer buf = bnd->vertex_buffers[i]; - if (buf.id != SG_INVALID_ID) { - igSeparator(); - igText("Vertex Buffer Slot #%d:", i); - igText(" Buffer: "); igSameLine(0,-1); - if (_sgimgui_draw_buffer_link(ctx, buf)) { - _sgimgui_show_buffer(ctx, buf); - } - igText(" Offset: %d", bnd->vertex_buffer_offsets[i]); - } else { - break; - } - } - if (bnd->index_buffer.id != SG_INVALID_ID) { - sg_buffer buf = bnd->index_buffer; - if (buf.id != SG_INVALID_ID) { - igSeparator(); - igText("Index Buffer Slot:"); - igText(" Buffer: "); igSameLine(0,-1); - if (_sgimgui_draw_buffer_link(ctx, buf)) { - _sgimgui_show_buffer(ctx, buf); - } - igText(" Offset: %d", bnd->index_buffer_offset); - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { - sg_image img = bnd->vs.images[i]; - if (img.id != SG_INVALID_ID) { - igSeparator(); - igText("Vertex Stage Image Slot #%d:", i); - igText(" Image: "); igSameLine(0,-1); - if (_sgimgui_draw_image_link(ctx, img)) { - _sgimgui_show_image(ctx, img); - } - } else { - break; - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++) { - sg_sampler smp = bnd->vs.samplers[i]; - if (smp.id != SG_INVALID_ID) { - igSeparator(); - igText("Vertex Stage Sampler Slot #%d:", i); - igText(" Sampler: "); igSameLine(0,-1); - if (_sgimgui_draw_sampler_link(ctx, smp)) { - _sgimgui_show_sampler(ctx, smp); - } - } else { - break; - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { - sg_buffer buf = bnd->vs.storage_buffers[i]; - if (buf.id != SG_INVALID_ID) { - igSeparator(); - igText("Vertex Stage Storage Buffer Slot #%d:", i); - igText(" Buffer: "); igSameLine(0,-1); - if (_sgimgui_draw_buffer_link(ctx, buf)) { - _sgimgui_show_buffer(ctx, buf); - } - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { - sg_image img = bnd->fs.images[i]; - if (img.id != SG_INVALID_ID) { - igSeparator(); - igText("Fragment Stage Image Slot #%d:", i); - igText(" Image: "); igSameLine(0,-1); - if (_sgimgui_draw_image_link(ctx, img)) { - _sgimgui_show_image(ctx, img); - } - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_SAMPLERS; i++) { - sg_sampler smp = bnd->fs.samplers[i]; - if (smp.id != SG_INVALID_ID) { - igSeparator(); - igText("Fragment Stage Sampler Slot #%d:", i); - igText(" Sampler: "); igSameLine(0,-1); - if (_sgimgui_draw_sampler_link(ctx, smp)) { - _sgimgui_show_sampler(ctx, smp); - } - } - } - for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { - sg_buffer buf = bnd->fs.storage_buffers[i]; - if (buf.id != SG_INVALID_ID) { - igSeparator(); - igText("Fragment Stage Storage Buffer Slot #%d:", i); - igText(" Buffer: "); igSameLine(0,-1); - if (_sgimgui_draw_buffer_link(ctx, buf)) { - _sgimgui_show_buffer(ctx, buf); - } - } - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_uniforms_panel(sgimgui_t* ctx, const sgimgui_args_apply_uniforms_t* args) { - SOKOL_ASSERT(args->ub_index < SG_MAX_VERTEX_BUFFERS); - - /* check if all the required information for drawing the structured uniform block content - is available, otherwise just render a generic hexdump - */ - if (sg_query_pipeline_state(args->pipeline) != SG_RESOURCESTATE_VALID) { - igText("Pipeline object not valid!"); - return; - } - sgimgui_pipeline_t* pip_ui = &ctx->pipeline_window.slots[_sgimgui_slot_index(args->pipeline.id)]; - if (sg_query_shader_state(pip_ui->desc.shader) != SG_RESOURCESTATE_VALID) { - igText("Shader object not valid!"); - return; - } - sgimgui_shader_t* shd_ui = &ctx->shader_window.slots[_sgimgui_slot_index(pip_ui->desc.shader.id)]; - SOKOL_ASSERT(shd_ui->res_id.id == pip_ui->desc.shader.id); - const sg_shader_uniform_block_desc* ub_desc = (args->stage == SG_SHADERSTAGE_VS) ? - &shd_ui->desc.vs.uniform_blocks[args->ub_index] : - &shd_ui->desc.fs.uniform_blocks[args->ub_index]; - SOKOL_ASSERT(args->data_size <= ub_desc->size); - bool draw_dump = false; - if (ub_desc->uniforms[0].type == SG_UNIFORMTYPE_INVALID) { - draw_dump = true; - } - - sgimgui_capture_bucket_t* bucket = _sgimgui_capture_get_read_bucket(ctx); - SOKOL_ASSERT((args->ubuf_pos + args->data_size) <= bucket->ubuf_size); - const float* uptrf = (const float*) (bucket->ubuf + args->ubuf_pos); - const int32_t* uptri32 = (const int32_t*) uptrf; - if (!draw_dump) { - uint32_t u_off = 0; - for (int i = 0; i < SG_MAX_UB_MEMBERS; i++) { - const sg_shader_uniform_desc* ud = &ub_desc->uniforms[i]; - if (ud->type == SG_UNIFORMTYPE_INVALID) { - break; - } - int num_items = (ud->array_count > 1) ? ud->array_count : 1; - if (num_items > 1) { - igText("%d: %s %s[%d] =", i, _sgimgui_uniformtype_string(ud->type), ud->name?ud->name:"", ud->array_count); - } else { - igText("%d: %s %s =", i, _sgimgui_uniformtype_string(ud->type), ud->name?ud->name:""); - } - for (int item_index = 0; item_index < num_items; item_index++) { - const uint32_t u_size = _sgimgui_std140_uniform_size(ud->type, ud->array_count) / 4; - const uint32_t u_align = _sgimgui_std140_uniform_alignment(ud->type, ud->array_count) / 4; - u_off = _sgimgui_align_u32(u_off, u_align); - switch (ud->type) { - case SG_UNIFORMTYPE_FLOAT: - igText(" %.3f", uptrf[u_off]); - break; - case SG_UNIFORMTYPE_INT: - igText(" %d", uptri32[u_off]); - break; - case SG_UNIFORMTYPE_FLOAT2: - igText(" %.3f, %.3f", uptrf[u_off], uptrf[u_off+1]); - break; - case SG_UNIFORMTYPE_INT2: - igText(" %d, %d", uptri32[u_off], uptri32[u_off+1]); - break; - case SG_UNIFORMTYPE_FLOAT3: - igText(" %.3f, %.3f, %.3f", uptrf[u_off], uptrf[u_off+1], uptrf[u_off+2]); - break; - case SG_UNIFORMTYPE_INT3: - igText(" %d, %d, %d", uptri32[u_off], uptri32[u_off+1], uptri32[u_off+2]); - break; - case SG_UNIFORMTYPE_FLOAT4: - igText(" %.3f, %.3f, %.3f, %.3f", uptrf[u_off], uptrf[u_off+1], uptrf[u_off+2], uptrf[u_off+3]); - break; - case SG_UNIFORMTYPE_INT4: - igText(" %d, %d, %d, %d", uptri32[u_off], uptri32[u_off+1], uptri32[u_off+2], uptri32[u_off+3]); - break; - case SG_UNIFORMTYPE_MAT4: - igText(" %.3f, %.3f, %.3f, %.3f\n" - " %.3f, %.3f, %.3f, %.3f\n" - " %.3f, %.3f, %.3f, %.3f\n" - " %.3f, %.3f, %.3f, %.3f", - uptrf[u_off+0], uptrf[u_off+1], uptrf[u_off+2], uptrf[u_off+3], - uptrf[u_off+4], uptrf[u_off+5], uptrf[u_off+6], uptrf[u_off+7], - uptrf[u_off+8], uptrf[u_off+9], uptrf[u_off+10], uptrf[u_off+11], - uptrf[u_off+12], uptrf[u_off+13], uptrf[u_off+14], uptrf[u_off+15]); - break; - default: - igText("???"); - break; - } - u_off += u_size; - } - } - } else { - // FIXME: float vs int - const size_t num_floats = ub_desc->size / sizeof(float); - for (uint32_t i = 0; i < num_floats; i++) { - igText("%.3f, ", uptrf[i]); - if (((i + 1) % 4) != 0) { - igSameLine(0,-1); - } - } - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_passaction_panel(sgimgui_t* ctx, sg_attachments atts, const sg_pass_action* action) { - /* determine number of valid color attachments */ - int num_color_atts = 0; - if (SG_INVALID_ID == atts.id) { - /* a swapchain pass: one color attachment */ - num_color_atts = 1; - } else { - const sgimgui_attachments_t* atts_ui = &ctx->attachments_window.slots[_sgimgui_slot_index(atts.id)]; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (atts_ui->desc.colors[i].image.id != SG_INVALID_ID) { - num_color_atts++; - } - } - } - - igText("Pass Action: "); - for (int i = 0; i < num_color_atts; i++) { - const sg_color_attachment_action* c_att = &action->colors[i]; - igText(" Color Attachment %d:", i); - sgimgui_str_t color_str; - switch (c_att->load_action) { - case SG_LOADACTION_LOAD: igText(" SG_LOADACTION_LOAD"); break; - case SG_LOADACTION_DONTCARE: igText(" SG_LOADACTION_DONTCARE"); break; - case SG_LOADACTION_CLEAR: - igText(" SG_LOADACTION_CLEAR: %s", _sgimgui_color_string(&color_str, c_att->clear_value)); - break; - default: igText(" ???"); break; - } - switch (c_att->store_action) { - case SG_STOREACTION_STORE: igText(" SG_STOREACTION_STORE"); break; - case SG_STOREACTION_DONTCARE: igText(" SG_STOREACTION_DONTCARE"); break; - default: igText(" ???"); break; - } - } - const sg_depth_attachment_action* d_att = &action->depth; - igText(" Depth Attachment:"); - switch (d_att->load_action) { - case SG_LOADACTION_LOAD: igText(" SG_LOADACTION_LOAD"); break; - case SG_LOADACTION_DONTCARE: igText(" SG_LOADACTION_DONTCARE"); break; - case SG_LOADACTION_CLEAR: igText(" SG_LOADACTION_CLEAR: %.3f", d_att->clear_value); break; - default: igText(" ???"); break; - } - switch (d_att->store_action) { - case SG_STOREACTION_STORE: igText(" SG_STOREACTION_STORE"); break; - case SG_STOREACTION_DONTCARE: igText(" SG_STOREACTION_DONTCARE"); break; - default: igText(" ???"); break; - } - const sg_stencil_attachment_action* s_att = &action->stencil; - igText(" Stencil Attachment"); - switch (s_att->load_action) { - case SG_LOADACTION_LOAD: igText(" SG_LOADACTION_LOAD"); break; - case SG_LOADACTION_DONTCARE: igText(" SG_LOADACTION_DONTCARE"); break; - case SG_LOADACTION_CLEAR: igText(" SG_LOADACTION_CLEAR: 0x%02X", s_att->clear_value); break; - default: igText(" ???"); break; - } - switch (d_att->store_action) { - case SG_STOREACTION_STORE: igText(" SG_STOREACTION_STORE"); break; - case SG_STOREACTION_DONTCARE: igText(" SG_STOREACTION_DONTCARE"); break; - default: igText(" ???"); break; - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_swapchain_panel(sg_swapchain* swapchain) { - igText("Swapchain"); - igText(" Width: %d", swapchain->width); - igText(" Height: %d", swapchain->height); - igText(" Sample Count: %d", swapchain->sample_count); - igText(" Color Format: %s", _sgimgui_pixelformat_string(swapchain->color_format)); - igText(" Depth Format: %s", _sgimgui_pixelformat_string(swapchain->depth_format)); - igSeparator(); - switch (sg_query_backend()) { - case SG_BACKEND_D3D11: - igText("D3D11 Objects:"); - igText(" Render View: %p", swapchain->d3d11.render_view); - igText(" Resolve View: %p", swapchain->d3d11.resolve_view); - igText(" Depth Stencil View: %p", swapchain->d3d11.depth_stencil_view); - break; - case SG_BACKEND_WGPU: - igText("WGPU Objects:"); - igText(" Render View: %p", swapchain->wgpu.render_view); - igText(" Resolve View: %p", swapchain->wgpu.resolve_view); - igText(" Depth Stencil View: %p", swapchain->wgpu.depth_stencil_view); - break; - case SG_BACKEND_METAL_MACOS: - case SG_BACKEND_METAL_IOS: - case SG_BACKEND_METAL_SIMULATOR: - igText("Metal Objects:"); - igText(" Current Drawable: %p", swapchain->metal.current_drawable); - igText(" Depth Stencil Texture: %p", swapchain->metal.depth_stencil_texture); - igText(" MSAA Color Texture: %p", swapchain->metal.msaa_color_texture); - break; - case SG_BACKEND_GLCORE: - case SG_BACKEND_GLES3: - igText("GL Objects:"); - igText(" Framebuffer: %d", swapchain->gl.framebuffer); - break; - default: - igText(" UNKNOWN BACKEND!"); - break; - } -} - -_SOKOL_PRIVATE void _sgimgui_draw_capture_panel(sgimgui_t* ctx) { - int sel_item_index = ctx->capture_window.sel_item; - if (sel_item_index >= _sgimgui_capture_num_read_items(ctx)) { - return; - } - sgimgui_capture_item_t* item = _sgimgui_capture_read_item_at(ctx, sel_item_index); - igBeginChild_Str("capture_item", IMVEC2(0, 0), false, 0); - igPushStyleColor_U32(ImGuiCol_Text, item->color); - igText("%s", _sgimgui_capture_item_string(ctx, sel_item_index, item).buf); - igPopStyleColor(1); - igSeparator(); - switch (item->cmd) { - case SGIMGUI_CMD_RESET_STATE_CACHE: - break; - case SGIMGUI_CMD_MAKE_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.make_buffer.result); - break; - case SGIMGUI_CMD_MAKE_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.make_image.result); - break; - case SGIMGUI_CMD_MAKE_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.make_sampler.result); - break; - case SGIMGUI_CMD_MAKE_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.make_shader.result); - break; - case SGIMGUI_CMD_MAKE_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.make_pipeline.result); - break; - case SGIMGUI_CMD_MAKE_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.make_attachments.result); - break; - case SGIMGUI_CMD_DESTROY_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.destroy_buffer.buffer); - break; - case SGIMGUI_CMD_DESTROY_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.destroy_image.image); - break; - case SGIMGUI_CMD_DESTROY_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.destroy_sampler.sampler); - break; - case SGIMGUI_CMD_DESTROY_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.destroy_shader.shader); - break; - case SGIMGUI_CMD_DESTROY_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.destroy_pipeline.pipeline); - break; - case SGIMGUI_CMD_DESTROY_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.destroy_attachments.attachments); - break; - case SGIMGUI_CMD_UPDATE_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.update_buffer.buffer); - break; - case SGIMGUI_CMD_UPDATE_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.update_image.image); - break; - case SGIMGUI_CMD_APPEND_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.update_buffer.buffer); - break; - case SGIMGUI_CMD_BEGIN_PASS: - _sgimgui_draw_passaction_panel(ctx, item->args.begin_pass.pass.attachments, &item->args.begin_pass.pass.action); - igSeparator(); - if (item->args.begin_pass.pass.attachments.id != SG_INVALID_ID) { - _sgimgui_draw_attachments_panel(ctx, item->args.begin_pass.pass.attachments); - } else { - _sgimgui_draw_swapchain_panel(&item->args.begin_pass.pass.swapchain); - } - break; - case SGIMGUI_CMD_APPLY_VIEWPORT: - case SGIMGUI_CMD_APPLY_SCISSOR_RECT: - break; - case SGIMGUI_CMD_APPLY_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.apply_pipeline.pipeline); - break; - case SGIMGUI_CMD_APPLY_BINDINGS: - _sgimgui_draw_bindings_panel(ctx, &item->args.apply_bindings.bindings); - break; - case SGIMGUI_CMD_APPLY_UNIFORMS: - _sgimgui_draw_uniforms_panel(ctx, &item->args.apply_uniforms); - break; - case SGIMGUI_CMD_DRAW: - case SGIMGUI_CMD_END_PASS: - case SGIMGUI_CMD_COMMIT: - break; - case SGIMGUI_CMD_ALLOC_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.alloc_buffer.result); - break; - case SGIMGUI_CMD_ALLOC_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.alloc_image.result); - break; - case SGIMGUI_CMD_ALLOC_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.alloc_sampler.result); - break; - case SGIMGUI_CMD_ALLOC_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.alloc_shader.result); - break; - case SGIMGUI_CMD_ALLOC_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.alloc_pipeline.result); - break; - case SGIMGUI_CMD_ALLOC_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.alloc_attachments.result); - break; - case SGIMGUI_CMD_INIT_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.init_buffer.buffer); - break; - case SGIMGUI_CMD_INIT_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.init_image.image); - break; - case SGIMGUI_CMD_INIT_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.init_sampler.sampler); - break; - case SGIMGUI_CMD_INIT_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.init_shader.shader); - break; - case SGIMGUI_CMD_INIT_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.init_pipeline.pipeline); - break; - case SGIMGUI_CMD_INIT_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.init_attachments.attachments); - break; - case SGIMGUI_CMD_FAIL_BUFFER: - _sgimgui_draw_buffer_panel(ctx, item->args.fail_buffer.buffer); - break; - case SGIMGUI_CMD_FAIL_IMAGE: - _sgimgui_draw_image_panel(ctx, item->args.fail_image.image); - break; - case SGIMGUI_CMD_FAIL_SAMPLER: - _sgimgui_draw_sampler_panel(ctx, item->args.fail_sampler.sampler); - break; - case SGIMGUI_CMD_FAIL_SHADER: - _sgimgui_draw_shader_panel(ctx, item->args.fail_shader.shader); - break; - case SGIMGUI_CMD_FAIL_PIPELINE: - _sgimgui_draw_pipeline_panel(ctx, item->args.fail_pipeline.pipeline); - break; - case SGIMGUI_CMD_FAIL_ATTACHMENTS: - _sgimgui_draw_attachments_panel(ctx, item->args.fail_attachments.attachments); - break; - default: - break; - } - igEndChild(); -} - -_SOKOL_PRIVATE void _sgimgui_draw_caps_panel(void) { - igText("Backend: %s\n\n", _sgimgui_backend_string(sg_query_backend())); - sg_features f = sg_query_features(); - igText("Features:"); - igText(" origin_top_left: %s", _sgimgui_bool_string(f.origin_top_left)); - igText(" image_clamp_to_border: %s", _sgimgui_bool_string(f.image_clamp_to_border)); - igText(" mrt_independent_blend_state: %s", _sgimgui_bool_string(f.mrt_independent_blend_state)); - igText(" mrt_independent_write_mask: %s", _sgimgui_bool_string(f.mrt_independent_write_mask)); - igText(" storage_buffer: %s", _sgimgui_bool_string(f.storage_buffer)); - sg_limits l = sg_query_limits(); - igText("\nLimits:\n"); - igText(" max_image_size_2d: %d", l.max_image_size_2d); - igText(" max_image_size_cube: %d", l.max_image_size_cube); - igText(" max_image_size_3d: %d", l.max_image_size_3d); - igText(" max_image_size_array: %d", l.max_image_size_array); - igText(" max_image_array_layers: %d", l.max_image_array_layers); - igText(" max_vertex_attrs: %d", l.max_vertex_attrs); - igText(" gl_max_vertex_uniform_components: %d", l.gl_max_vertex_uniform_components); - igText(" gl_max_combined_texture_image_units: %d", l.gl_max_combined_texture_image_units); - igText("\nUsable Pixelformats:"); - for (int i = (int)(SG_PIXELFORMAT_NONE+1); i < (int)_SG_PIXELFORMAT_NUM; i++) { - sg_pixel_format fmt = (sg_pixel_format)i; - sg_pixelformat_info info = sg_query_pixelformat(fmt); - if (info.sample) { - igText(" %s: %s%s%s%s%s%s", - _sgimgui_pixelformat_string(fmt), - info.sample ? "SAMPLE ":"", - info.filter ? "FILTER ":"", - info.blend ? "BLEND ":"", - info.render ? "RENDER ":"", - info.msaa ? "MSAA ":"", - info.depth ? "DEPTH ":""); - } - } -} - -_SOKOL_PRIVATE void _sgimgui_frame_add_stats_row(const char* key, uint32_t value) { - igTableNextRow(0, 0.0f); - igTableSetColumnIndex(0); - igText(key); - igTableSetColumnIndex(1); - igText("%d", value); -} - -#define _sgimgui_frame_stats(key) _sgimgui_frame_add_stats_row(#key, stats->key) - -_SOKOL_PRIVATE void _sgimgui_draw_frame_stats_panel(sgimgui_t* ctx) { - _SOKOL_UNUSED(ctx); - igCheckbox("Ignore sokol_imgui.h", &ctx->frame_stats_window.disable_sokol_imgui_stats); - const sg_frame_stats* stats = &ctx->frame_stats_window.stats; - const ImGuiTableFlags flags = - ImGuiTableFlags_Resizable | - ImGuiTableFlags_ScrollY | - ImGuiTableFlags_SizingFixedFit | - ImGuiTableFlags_Borders; - if (igBeginTable("##frame_stats_table", 2, flags, IMVEC2(0, 0), 0)) { - igTableSetupScrollFreeze(0, 1); - igTableSetupColumn("key", ImGuiTableColumnFlags_None, 0, 0); - igTableSetupColumn("value", ImGuiTableColumnFlags_None, 0, 0); - igTableHeadersRow(); - _sgimgui_frame_stats(frame_index); - _sgimgui_frame_stats(num_passes); - _sgimgui_frame_stats(num_apply_viewport); - _sgimgui_frame_stats(num_apply_scissor_rect); - _sgimgui_frame_stats(num_apply_pipeline); - _sgimgui_frame_stats(num_apply_bindings); - _sgimgui_frame_stats(num_apply_uniforms); - _sgimgui_frame_stats(num_draw); - _sgimgui_frame_stats(num_update_buffer); - _sgimgui_frame_stats(num_append_buffer); - _sgimgui_frame_stats(num_update_image); - _sgimgui_frame_stats(size_apply_uniforms); - _sgimgui_frame_stats(size_update_buffer); - _sgimgui_frame_stats(size_append_buffer); - _sgimgui_frame_stats(size_update_image); - switch (sg_query_backend()) { - case SG_BACKEND_GLCORE: - case SG_BACKEND_GLES3: - _sgimgui_frame_stats(gl.num_bind_buffer); - _sgimgui_frame_stats(gl.num_active_texture); - _sgimgui_frame_stats(gl.num_bind_texture); - _sgimgui_frame_stats(gl.num_bind_sampler); - _sgimgui_frame_stats(gl.num_use_program); - _sgimgui_frame_stats(gl.num_render_state); - _sgimgui_frame_stats(gl.num_vertex_attrib_pointer); - _sgimgui_frame_stats(gl.num_vertex_attrib_divisor); - _sgimgui_frame_stats(gl.num_enable_vertex_attrib_array); - _sgimgui_frame_stats(gl.num_disable_vertex_attrib_array); - _sgimgui_frame_stats(gl.num_uniform); - break; - case SG_BACKEND_WGPU: - _sgimgui_frame_stats(wgpu.uniforms.num_set_bindgroup); - _sgimgui_frame_stats(wgpu.uniforms.size_write_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_set_vertex_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_skip_redundant_vertex_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_set_index_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_skip_redundant_index_buffer); - _sgimgui_frame_stats(wgpu.bindings.num_create_bindgroup); - _sgimgui_frame_stats(wgpu.bindings.num_discard_bindgroup); - _sgimgui_frame_stats(wgpu.bindings.num_set_bindgroup); - _sgimgui_frame_stats(wgpu.bindings.num_skip_redundant_bindgroup); - _sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_hits); - _sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_misses); - _sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_collisions); - _sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_invalidates); - _sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_hash_vs_key_mismatch); - break; - case SG_BACKEND_METAL_MACOS: - case SG_BACKEND_METAL_IOS: - case SG_BACKEND_METAL_SIMULATOR: - _sgimgui_frame_stats(metal.idpool.num_added); - _sgimgui_frame_stats(metal.idpool.num_released); - _sgimgui_frame_stats(metal.idpool.num_garbage_collected); - _sgimgui_frame_stats(metal.pipeline.num_set_blend_color); - _sgimgui_frame_stats(metal.pipeline.num_set_cull_mode); - _sgimgui_frame_stats(metal.pipeline.num_set_front_facing_winding); - _sgimgui_frame_stats(metal.pipeline.num_set_stencil_reference_value); - _sgimgui_frame_stats(metal.pipeline.num_set_depth_bias); - _sgimgui_frame_stats(metal.pipeline.num_set_render_pipeline_state); - _sgimgui_frame_stats(metal.pipeline.num_set_depth_stencil_state); - _sgimgui_frame_stats(metal.bindings.num_set_vertex_buffer); - _sgimgui_frame_stats(metal.bindings.num_set_vertex_texture); - _sgimgui_frame_stats(metal.bindings.num_set_vertex_sampler_state); - _sgimgui_frame_stats(metal.bindings.num_set_fragment_buffer); - _sgimgui_frame_stats(metal.bindings.num_set_fragment_texture); - _sgimgui_frame_stats(metal.bindings.num_set_fragment_sampler_state); - _sgimgui_frame_stats(metal.uniforms.num_set_vertex_buffer_offset); - _sgimgui_frame_stats(metal.uniforms.num_set_fragment_buffer_offset); - break; - case SG_BACKEND_D3D11: - _sgimgui_frame_stats(d3d11.pass.num_om_set_render_targets); - _sgimgui_frame_stats(d3d11.pass.num_clear_render_target_view); - _sgimgui_frame_stats(d3d11.pass.num_clear_depth_stencil_view); - _sgimgui_frame_stats(d3d11.pass.num_resolve_subresource); - _sgimgui_frame_stats(d3d11.pipeline.num_rs_set_state); - _sgimgui_frame_stats(d3d11.pipeline.num_om_set_depth_stencil_state); - _sgimgui_frame_stats(d3d11.pipeline.num_om_set_blend_state); - _sgimgui_frame_stats(d3d11.pipeline.num_ia_set_primitive_topology); - _sgimgui_frame_stats(d3d11.pipeline.num_ia_set_input_layout); - _sgimgui_frame_stats(d3d11.pipeline.num_vs_set_shader); - _sgimgui_frame_stats(d3d11.pipeline.num_vs_set_constant_buffers); - _sgimgui_frame_stats(d3d11.pipeline.num_ps_set_shader); - _sgimgui_frame_stats(d3d11.pipeline.num_ps_set_constant_buffers); - _sgimgui_frame_stats(d3d11.bindings.num_ia_set_vertex_buffers); - _sgimgui_frame_stats(d3d11.bindings.num_ia_set_index_buffer); - _sgimgui_frame_stats(d3d11.bindings.num_vs_set_shader_resources); - _sgimgui_frame_stats(d3d11.bindings.num_ps_set_shader_resources); - _sgimgui_frame_stats(d3d11.bindings.num_vs_set_samplers); - _sgimgui_frame_stats(d3d11.bindings.num_ps_set_samplers); - _sgimgui_frame_stats(d3d11.uniforms.num_update_subresource); - _sgimgui_frame_stats(d3d11.draw.num_draw_indexed_instanced); - _sgimgui_frame_stats(d3d11.draw.num_draw_indexed); - _sgimgui_frame_stats(d3d11.draw.num_draw_instanced); - _sgimgui_frame_stats(d3d11.draw.num_draw); - _sgimgui_frame_stats(d3d11.num_map); - _sgimgui_frame_stats(d3d11.num_unmap); - break; - default: break; - } - igEndTable(); - } -} - -#define _sgimgui_def(val, def) (((val) == 0) ? (def) : (val)) - -_SOKOL_PRIVATE sgimgui_desc_t _sgimgui_desc_defaults(const sgimgui_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sgimgui_desc_t res = *desc; - // FIXME: any additional default overrides would go here - return res; -} - -/*--- PUBLIC FUNCTIONS -------------------------------------------------------*/ -SOKOL_API_IMPL void sgimgui_init(sgimgui_t* ctx, const sgimgui_desc_t* desc) { - SOKOL_ASSERT(ctx && desc); - _sgimgui_clear(ctx, sizeof(sgimgui_t)); - ctx->init_tag = 0xABCDABCD; - ctx->desc = _sgimgui_desc_defaults(desc); - _sgimgui_capture_init(ctx); - - /* hook into sokol_gfx functions */ - sg_trace_hooks hooks; - _sgimgui_clear(&hooks, sizeof(hooks)); - hooks.user_data = (void*) ctx; - hooks.reset_state_cache = _sgimgui_reset_state_cache; - hooks.make_buffer = _sgimgui_make_buffer; - hooks.make_image = _sgimgui_make_image; - hooks.make_sampler = _sgimgui_make_sampler; - hooks.make_shader = _sgimgui_make_shader; - hooks.make_pipeline = _sgimgui_make_pipeline; - hooks.make_attachments = _sgimgui_make_attachments; - hooks.destroy_buffer = _sgimgui_destroy_buffer; - hooks.destroy_image = _sgimgui_destroy_image; - hooks.destroy_sampler = _sgimgui_destroy_sampler; - hooks.destroy_shader = _sgimgui_destroy_shader; - hooks.destroy_pipeline = _sgimgui_destroy_pipeline; - hooks.destroy_attachments = _sgimgui_destroy_attachments; - hooks.update_buffer = _sgimgui_update_buffer; - hooks.update_image = _sgimgui_update_image; - hooks.append_buffer = _sgimgui_append_buffer; - hooks.begin_pass = _sgimgui_begin_pass; - hooks.apply_viewport = _sgimgui_apply_viewport; - hooks.apply_scissor_rect = _sgimgui_apply_scissor_rect; - hooks.apply_pipeline = _sgimgui_apply_pipeline; - hooks.apply_bindings = _sgimgui_apply_bindings; - hooks.apply_uniforms = _sgimgui_apply_uniforms; - hooks.draw = _sgimgui_draw; - hooks.end_pass = _sgimgui_end_pass; - hooks.commit = _sgimgui_commit; - hooks.alloc_buffer = _sgimgui_alloc_buffer; - hooks.alloc_image = _sgimgui_alloc_image; - hooks.alloc_sampler = _sgimgui_alloc_sampler; - hooks.alloc_shader = _sgimgui_alloc_shader; - hooks.alloc_pipeline = _sgimgui_alloc_pipeline; - hooks.alloc_attachments = _sgimgui_alloc_attachments; - hooks.dealloc_buffer = _sgimgui_dealloc_buffer; - hooks.dealloc_image = _sgimgui_dealloc_image; - hooks.dealloc_sampler = _sgimgui_dealloc_sampler; - hooks.dealloc_shader = _sgimgui_dealloc_shader; - hooks.dealloc_pipeline = _sgimgui_dealloc_pipeline; - hooks.dealloc_attachments = _sgimgui_dealloc_attachments; - hooks.init_buffer = _sgimgui_init_buffer; - hooks.init_image = _sgimgui_init_image; - hooks.init_sampler = _sgimgui_init_sampler; - hooks.init_shader = _sgimgui_init_shader; - hooks.init_pipeline = _sgimgui_init_pipeline; - hooks.init_attachments = _sgimgui_init_attachments; - hooks.uninit_buffer = _sgimgui_uninit_buffer; - hooks.uninit_image = _sgimgui_uninit_image; - hooks.uninit_sampler = _sgimgui_uninit_sampler; - hooks.uninit_shader = _sgimgui_uninit_shader; - hooks.uninit_pipeline = _sgimgui_uninit_pipeline; - hooks.uninit_attachments = _sgimgui_uninit_attachments; - hooks.fail_buffer = _sgimgui_fail_buffer; - hooks.fail_image = _sgimgui_fail_image; - hooks.fail_sampler = _sgimgui_fail_sampler; - hooks.fail_shader = _sgimgui_fail_shader; - hooks.fail_pipeline = _sgimgui_fail_pipeline; - hooks.fail_attachments = _sgimgui_fail_attachments; - hooks.push_debug_group = _sgimgui_push_debug_group; - hooks.pop_debug_group = _sgimgui_pop_debug_group; - ctx->hooks = sg_install_trace_hooks(&hooks); - - /* allocate resource debug-info slots */ - const sg_desc sgdesc = sg_query_desc(); - ctx->buffer_window.num_slots = sgdesc.buffer_pool_size; - ctx->image_window.num_slots = sgdesc.image_pool_size; - ctx->sampler_window.num_slots = sgdesc.sampler_pool_size; - ctx->shader_window.num_slots = sgdesc.shader_pool_size; - ctx->pipeline_window.num_slots = sgdesc.pipeline_pool_size; - ctx->attachments_window.num_slots = sgdesc.attachments_pool_size; - - const size_t buffer_pool_size = (size_t)ctx->buffer_window.num_slots * sizeof(sgimgui_buffer_t); - ctx->buffer_window.slots = (sgimgui_buffer_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, buffer_pool_size); - - const size_t image_pool_size = (size_t)ctx->image_window.num_slots * sizeof(sgimgui_image_t); - ctx->image_window.slots = (sgimgui_image_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, image_pool_size); - - const size_t sampler_pool_size = (size_t)ctx->sampler_window.num_slots * sizeof(sgimgui_sampler_t); - ctx->sampler_window.slots = (sgimgui_sampler_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, sampler_pool_size); - - const size_t shader_pool_size = (size_t)ctx->shader_window.num_slots * sizeof(sgimgui_shader_t); - ctx->shader_window.slots = (sgimgui_shader_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, shader_pool_size); - - const size_t pipeline_pool_size = (size_t)ctx->pipeline_window.num_slots * sizeof(sgimgui_pipeline_t); - ctx->pipeline_window.slots = (sgimgui_pipeline_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, pipeline_pool_size); - - const size_t attachments_pool_size = (size_t)ctx->attachments_window.num_slots * sizeof(sgimgui_attachments_t); - ctx->attachments_window.slots = (sgimgui_attachments_t*) _sgimgui_malloc_clear(&ctx->desc.allocator, attachments_pool_size); -} - -SOKOL_API_IMPL void sgimgui_discard(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - /* restore original trace hooks */ - sg_install_trace_hooks(&ctx->hooks); - ctx->init_tag = 0; - _sgimgui_capture_discard(ctx); - if (ctx->buffer_window.slots) { - for (int i = 0; i < ctx->buffer_window.num_slots; i++) { - if (ctx->buffer_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_buffer_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->buffer_window.slots); - ctx->buffer_window.slots = 0; - } - if (ctx->image_window.slots) { - for (int i = 0; i < ctx->image_window.num_slots; i++) { - if (ctx->image_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_image_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->image_window.slots); - ctx->image_window.slots = 0; - } - if (ctx->sampler_window.slots) { - for (int i = 0; i < ctx->sampler_window.num_slots; i++) { - if (ctx->sampler_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_sampler_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->sampler_window.slots); - ctx->sampler_window.slots = 0; - } - if (ctx->shader_window.slots) { - for (int i = 0; i < ctx->shader_window.num_slots; i++) { - if (ctx->shader_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_shader_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->shader_window.slots); - ctx->shader_window.slots = 0; - } - if (ctx->pipeline_window.slots) { - for (int i = 0; i < ctx->pipeline_window.num_slots; i++) { - if (ctx->pipeline_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_pipeline_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->pipeline_window.slots); - ctx->pipeline_window.slots = 0; - } - if (ctx->attachments_window.slots) { - for (int i = 0; i < ctx->attachments_window.num_slots; i++) { - if (ctx->attachments_window.slots[i].res_id.id != SG_INVALID_ID) { - _sgimgui_attachments_destroyed(ctx, i); - } - } - _sgimgui_free(&ctx->desc.allocator, (void*)ctx->attachments_window.slots); - ctx->attachments_window.slots = 0; - } -} - -SOKOL_API_IMPL void sgimgui_draw(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - sgimgui_draw_buffer_window(ctx); - sgimgui_draw_image_window(ctx); - sgimgui_draw_sampler_window(ctx); - sgimgui_draw_shader_window(ctx); - sgimgui_draw_pipeline_window(ctx); - sgimgui_draw_attachments_window(ctx); - sgimgui_draw_capture_window(ctx); - sgimgui_draw_capabilities_window(ctx); - sgimgui_draw_frame_stats_window(ctx); -} - -SOKOL_API_IMPL void sgimgui_draw_menu(sgimgui_t* ctx, const char* title) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - SOKOL_ASSERT(title); - if (igBeginMenu(title, true)) { - igMenuItem_BoolPtr("Capabilities", 0, &ctx->caps_window.open, true); - igMenuItem_BoolPtr("Frame Stats", 0, &ctx->frame_stats_window.open, true); - igMenuItem_BoolPtr("Buffers", 0, &ctx->buffer_window.open, true); - igMenuItem_BoolPtr("Images", 0, &ctx->image_window.open, true); - igMenuItem_BoolPtr("Samplers", 0, &ctx->sampler_window.open, true); - igMenuItem_BoolPtr("Shaders", 0, &ctx->shader_window.open, true); - igMenuItem_BoolPtr("Pipelines", 0, &ctx->pipeline_window.open, true); - igMenuItem_BoolPtr("Attachments", 0, &ctx->attachments_window.open, true); - igMenuItem_BoolPtr("Calls", 0, &ctx->capture_window.open, true); - igEndMenu(); - } -} - -SOKOL_API_IMPL void sgimgui_draw_buffer_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->buffer_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 280), ImGuiCond_Once); - if (igBegin("Buffers", &ctx->buffer_window.open, 0)) { - sgimgui_draw_buffer_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_image_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->image_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Images", &ctx->image_window.open, 0)) { - sgimgui_draw_image_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_sampler_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->sampler_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Samplers", &ctx->sampler_window.open, 0)) { - sgimgui_draw_sampler_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_shader_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->shader_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Shaders", &ctx->shader_window.open, 0)) { - sgimgui_draw_shader_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_pipeline_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->pipeline_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(540, 400), ImGuiCond_Once); - if (igBegin("Pipelines", &ctx->pipeline_window.open, 0)) { - sgimgui_draw_pipeline_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_attachments_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->attachments_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Attachments", &ctx->attachments_window.open, 0)) { - sgimgui_draw_attachments_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_capture_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->capture_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(640, 400), ImGuiCond_Once); - if (igBegin("Frame Capture", &ctx->capture_window.open, 0)) { - sgimgui_draw_capture_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_capabilities_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->caps_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(440, 400), ImGuiCond_Once); - if (igBegin("Capabilities", &ctx->caps_window.open, 0)) { - sgimgui_draw_capabilities_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_frame_stats_window(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - if (!ctx->frame_stats_window.open) { - return; - } - igSetNextWindowSize(IMVEC2(512, 400), ImGuiCond_Once); - if (igBegin("Frame Stats", &ctx->frame_stats_window.open, 0)) { - sgimgui_draw_frame_stats_window_content(ctx); - } - igEnd(); -} - -SOKOL_API_IMPL void sgimgui_draw_buffer_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_buffer_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_buffer_panel(ctx, ctx->buffer_window.sel_buf); -} - -SOKOL_API_IMPL void sgimgui_draw_image_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_image_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_image_panel(ctx, ctx->image_window.sel_img); -} - -SOKOL_API_IMPL void sgimgui_draw_sampler_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_sampler_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_sampler_panel(ctx, ctx->sampler_window.sel_smp); -} - -SOKOL_API_IMPL void sgimgui_draw_shader_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_shader_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_shader_panel(ctx, ctx->shader_window.sel_shd); -} - -SOKOL_API_IMPL void sgimgui_draw_pipeline_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_pipeline_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_pipeline_panel(ctx, ctx->pipeline_window.sel_pip); -} - -SOKOL_API_IMPL void sgimgui_draw_attachments_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_attachments_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_attachments_panel(ctx, ctx->attachments_window.sel_atts); -} - -SOKOL_API_IMPL void sgimgui_draw_capture_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _sgimgui_draw_capture_list(ctx); - igSameLine(0,-1); - _sgimgui_draw_capture_panel(ctx); -} - -SOKOL_API_IMPL void sgimgui_draw_capabilities_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - _SOKOL_UNUSED(ctx); - _sgimgui_draw_caps_panel(); -} - -SOKOL_API_IMPL void sgimgui_draw_frame_stats_window_content(sgimgui_t* ctx) { - SOKOL_ASSERT(ctx && (ctx->init_tag == 0xABCDABCD)); - ctx->frame_stats_window.stats = sg_query_frame_stats(); - _sgimgui_draw_frame_stats_panel(ctx); -} - -#endif /* SOKOL_GFX_IMGUI_IMPL */ diff --git a/source/thirdparty/sokol/util/sokol_gl.h b/source/thirdparty/sokol/util/sokol_gl.h deleted file mode 100644 index 654cb0f6..00000000 --- a/source/thirdparty/sokol/util/sokol_gl.h +++ /dev/null @@ -1,4329 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_GL_IMPL) -#define SOKOL_GL_IMPL -#endif -#ifndef SOKOL_GL_INCLUDED -/* - 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. -*/ -#define SOKOL_GL_INCLUDED (1) -#include -#include -#include // size_t, offsetof - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_gl.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_GL_API_DECL) -#define SOKOL_GL_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_GL_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GL_IMPL) -#define SOKOL_GL_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_GL_API_DECL __declspec(dllimport) -#else -#define SOKOL_GL_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - sgl_log_item_t - - Log items are defined via X-Macros, and expanded to an - enum 'sgl_log_item' - and in debug mode only - corresponding strings. - - Used as parameter in the logging callback. -*/ -#define _SGL_LOG_ITEMS \ - _SGL_LOGITEM_XMACRO(OK, "Ok") \ - _SGL_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SGL_LOGITEM_XMACRO(MAKE_PIPELINE_FAILED, "sg_make_pipeline() failed") \ - _SGL_LOGITEM_XMACRO(PIPELINE_POOL_EXHAUSTED, "pipeline pool exhausted (use sgl_desc_t.pipeline_pool_size to adjust)") \ - _SGL_LOGITEM_XMACRO(ADD_COMMIT_LISTENER_FAILED, "sg_add_commit_listener() failed") \ - _SGL_LOGITEM_XMACRO(CONTEXT_POOL_EXHAUSTED, "context pool exhausted (use sgl_desc_t.context_pool_size to adjust)") \ - _SGL_LOGITEM_XMACRO(CANNOT_DESTROY_DEFAULT_CONTEXT, "cannot destroy default context") \ - -#define _SGL_LOGITEM_XMACRO(item,msg) SGL_LOGITEM_##item, -typedef enum sgl_log_item_t { - _SGL_LOG_ITEMS -} sgl_log_item_t; -#undef _SGL_LOGITEM_XMACRO - -/* - sgl_logger_t - - Used in sgl_desc_t to provide a custom logging and error reporting - callback to sokol-gl. -*/ -typedef struct sgl_logger_t { - void (*func)( - const char* tag, // always "sgl" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 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); - void* user_data; -} sgl_logger_t; - -/* sokol_gl pipeline handle (created with sgl_make_pipeline()) */ -typedef struct sgl_pipeline { uint32_t id; } sgl_pipeline; - -/* a context handle (created with sgl_make_context()) */ -typedef struct sgl_context { uint32_t id; } sgl_context; - -/* - sgl_error_t - - Errors are reset each frame after calling sgl_draw(), - get the last error code with sgl_error() -*/ -typedef struct sgl_error_t { - bool any; - bool vertices_full; - bool uniforms_full; - bool commands_full; - bool stack_overflow; - bool stack_underflow; - bool no_context; -} sgl_error_t; - -/* - 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. -*/ -typedef struct sgl_context_desc_t { - int max_vertices; // default: 64k - int max_commands; // default: 16k - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; -} sgl_context_desc_t; - -/* - 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). -*/ -typedef struct sgl_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sgl_allocator_t; - -typedef struct sgl_desc_t { - int max_vertices; // default: 64k - int max_commands; // default: 16k - int context_pool_size; // max number of contexts (including default context), default: 4 - int pipeline_pool_size; // size of internal pipeline pool, default: 64 - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - sg_face_winding face_winding; // default: SG_FACEWINDING_CCW - sgl_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) - sgl_logger_t logger; // optional log function override (default: NO LOGGING) -} sgl_desc_t; - -/* the default context handle */ -static const sgl_context SGL_DEFAULT_CONTEXT = { 0x00010001 }; - -/* setup/shutdown/misc */ -SOKOL_GL_API_DECL void sgl_setup(const sgl_desc_t* desc); -SOKOL_GL_API_DECL void sgl_shutdown(void); -SOKOL_GL_API_DECL float sgl_rad(float deg); -SOKOL_GL_API_DECL float sgl_deg(float rad); -SOKOL_GL_API_DECL sgl_error_t sgl_error(void); -SOKOL_GL_API_DECL sgl_error_t sgl_context_error(sgl_context ctx); - -/* context functions */ -SOKOL_GL_API_DECL sgl_context sgl_make_context(const sgl_context_desc_t* desc); -SOKOL_GL_API_DECL void sgl_destroy_context(sgl_context ctx); -SOKOL_GL_API_DECL void sgl_set_context(sgl_context ctx); -SOKOL_GL_API_DECL sgl_context sgl_get_context(void); -SOKOL_GL_API_DECL sgl_context sgl_default_context(void); - -/* get information about recorded vertices and commands in current context */ -SOKOL_GL_API_DECL int sgl_num_vertices(void); -SOKOL_GL_API_DECL int sgl_num_commands(void); - -/* draw recorded commands (call inside a sokol-gfx render pass) */ -SOKOL_GL_API_DECL void sgl_draw(void); -SOKOL_GL_API_DECL void sgl_context_draw(sgl_context ctx); -SOKOL_GL_API_DECL void sgl_draw_layer(int layer_id); -SOKOL_GL_API_DECL void sgl_context_draw_layer(sgl_context ctx, int layer_id); - -/* create and destroy pipeline objects */ -SOKOL_GL_API_DECL sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc); -SOKOL_GL_API_DECL sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline_desc* desc); -SOKOL_GL_API_DECL void sgl_destroy_pipeline(sgl_pipeline pip); - -/* render state functions */ -SOKOL_GL_API_DECL void sgl_defaults(void); -SOKOL_GL_API_DECL void sgl_viewport(int x, int y, int w, int h, bool origin_top_left); -SOKOL_GL_API_DECL void sgl_viewportf(float x, float y, float w, float h, bool origin_top_left); -SOKOL_GL_API_DECL void sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left); -SOKOL_GL_API_DECL void sgl_scissor_rectf(float x, float y, float w, float h, bool origin_top_left); -SOKOL_GL_API_DECL void sgl_enable_texture(void); -SOKOL_GL_API_DECL void sgl_disable_texture(void); -SOKOL_GL_API_DECL void sgl_texture(sg_image img, sg_sampler smp); -SOKOL_GL_API_DECL void sgl_layer(int layer_id); - -/* pipeline stack functions */ -SOKOL_GL_API_DECL void sgl_load_default_pipeline(void); -SOKOL_GL_API_DECL void sgl_load_pipeline(sgl_pipeline pip); -SOKOL_GL_API_DECL void sgl_push_pipeline(void); -SOKOL_GL_API_DECL void sgl_pop_pipeline(void); - -/* matrix stack functions */ -SOKOL_GL_API_DECL void sgl_matrix_mode_modelview(void); -SOKOL_GL_API_DECL void sgl_matrix_mode_projection(void); -SOKOL_GL_API_DECL void sgl_matrix_mode_texture(void); -SOKOL_GL_API_DECL void sgl_load_identity(void); -SOKOL_GL_API_DECL void sgl_load_matrix(const float m[16]); -SOKOL_GL_API_DECL void sgl_load_transpose_matrix(const float m[16]); -SOKOL_GL_API_DECL void sgl_mult_matrix(const float m[16]); -SOKOL_GL_API_DECL void sgl_mult_transpose_matrix(const float m[16]); -SOKOL_GL_API_DECL void sgl_rotate(float angle_rad, float x, float y, float z); -SOKOL_GL_API_DECL void sgl_scale(float x, float y, float z); -SOKOL_GL_API_DECL void sgl_translate(float x, float y, float z); -SOKOL_GL_API_DECL void sgl_frustum(float l, float r, float b, float t, float n, float f); -SOKOL_GL_API_DECL void sgl_ortho(float l, float r, float b, float t, float n, float f); -SOKOL_GL_API_DECL void sgl_perspective(float fov_y, float aspect, float z_near, float z_far); -SOKOL_GL_API_DECL void 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); -SOKOL_GL_API_DECL void sgl_push_matrix(void); -SOKOL_GL_API_DECL void sgl_pop_matrix(void); - -/* these functions only set the internal 'current texcoord / color / point size' (valid inside or outside begin/end) */ -SOKOL_GL_API_DECL void sgl_t2f(float u, float v); -SOKOL_GL_API_DECL void sgl_c3f(float r, float g, float b); -SOKOL_GL_API_DECL void sgl_c4f(float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_c3b(uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_c4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_c1i(uint32_t rgba); -SOKOL_GL_API_DECL void sgl_point_size(float s); - -/* define primitives, each begin/end is one draw command */ -SOKOL_GL_API_DECL void sgl_begin_points(void); -SOKOL_GL_API_DECL void sgl_begin_lines(void); -SOKOL_GL_API_DECL void sgl_begin_line_strip(void); -SOKOL_GL_API_DECL void sgl_begin_triangles(void); -SOKOL_GL_API_DECL void sgl_begin_triangle_strip(void); -SOKOL_GL_API_DECL void sgl_begin_quads(void); -SOKOL_GL_API_DECL void sgl_v2f(float x, float y); -SOKOL_GL_API_DECL void sgl_v3f(float x, float y, float z); -SOKOL_GL_API_DECL void sgl_v2f_t2f(float x, float y, float u, float v); -SOKOL_GL_API_DECL void sgl_v3f_t2f(float x, float y, float z, float u, float v); -SOKOL_GL_API_DECL void sgl_v2f_c3f(float x, float y, float r, float g, float b); -SOKOL_GL_API_DECL void sgl_v2f_c3b(float x, float y, uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_v2f_c4f(float x, float y, float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_v2f_c4b(float x, float y, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_v2f_c1i(float x, float y, uint32_t rgba); -SOKOL_GL_API_DECL void sgl_v3f_c3f(float x, float y, float z, float r, float g, float b); -SOKOL_GL_API_DECL void sgl_v3f_c3b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_v3f_c4f(float x, float y, float z, float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_v3f_c4b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_v3f_c1i(float x, float y, float z, uint32_t rgba); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c3f(float x, float y, float u, float v, float r, float g, float b); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c3b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c4f(float x, float y, float u, float v, float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c4b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_v2f_t2f_c1i(float x, float y, float u, float v, uint32_t rgba); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c3f(float x, float y, float z, float u, float v, float r, float g, float b); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c3b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c4f(float x, float y, float z, float u, float v, float r, float g, float b, float a); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c4b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_GL_API_DECL void sgl_v3f_t2f_c1i(float x, float y, float z, float u, float v, uint32_t rgba); -SOKOL_GL_API_DECL void sgl_end(void); - -#ifdef __cplusplus -} /* extern "C" */ - -/* reference-based equivalents for C++ */ -inline void sgl_setup(const sgl_desc_t& desc) { return sgl_setup(&desc); } -inline sgl_context sgl_make_context(const sgl_context_desc_t& desc) { return sgl_make_context(&desc); } -inline sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc& desc) { return sgl_make_pipeline(&desc); } -inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline_desc& desc) { return sgl_context_make_pipeline(ctx, &desc); } -#endif -#endif /* SOKOL_GL_INCLUDED */ - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_GL_IMPL -#define SOKOL_GL_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sgl_desc_t.allocator to override memory allocation functions" -#endif - -#include // malloc/free -#include // memset -#include // M_PI, sqrtf, sinf, cosf - -#ifndef M_PI -#define M_PI 3.14159265358979323846264338327 -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#define _sgl_def(val, def) (((val) == 0) ? (def) : (val)) -#define _SGL_INIT_COOKIE (0xABCDABCD) - -/* - Embedded source code compiled with: - - sokol-shdc -i sgl.glsl -o sgl.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgpu -b - - (not that for Metal and D3D11 byte code, sokol-shdc must be run - on macOS and Windows) - - @vs vs - uniform vs_params { - mat4 mvp; - mat4 tm; - }; - in vec4 position; - in vec2 texcoord0; - in vec4 color0; - in float psize; - out vec4 uv; - out vec4 color; - void main() { - gl_Position = mvp * position; - #ifndef SOKOL_WGSL - gl_PointSize = psize; - #endif - uv = tm * vec4(texcoord0, 0.0, 1.0); - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - in vec4 uv; - in vec4 color; - out vec4 frag_color; - void main() { - frag_color = texture(sampler2D(tex, smp), uv.xy) * color; - } - @end - - @program sgl vs fs -*/ - -#if defined(SOKOL_GLCORE) -static const uint8_t _sgl_vs_source_glsl410[520] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, - 0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65, - 0x63,0x34,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f, - 0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76, - 0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6c, - 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, - 0x20,0x31,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, - 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, - 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53, - 0x69,0x7a,0x65,0x20,0x3d,0x20,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x75,0x76,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73, - 0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x37, - 0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sgl_fs_source_glsl410[222] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, - 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, - 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67, - 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65, - 0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x2e,0x78,0x79,0x29, - 0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_GLES3) -static const uint8_t _sgl_vs_source_glsl300es[481] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, - 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, - 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x20,0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x20,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74, - 0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79, - 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32, - 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b, - 0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b, - 0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d, - 0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20, - 0x2a,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x70, - 0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x6d, - 0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d, - 0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x37,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65, - 0x63,0x34,0x28,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e, - 0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a, - 0x00, -}; -static const uint8_t _sgl_fs_source_glsl300es[253] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, - 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x75, - 0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, - 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x2e,0x78,0x79,0x29,0x20, - 0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _sgl_vs_bytecode_metal_macos[3317] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf5,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x76,0x25,0x5f,0x37,0x22,0xd0,0x3f, - 0x64,0xef,0xff,0xc3,0x45,0x1a,0x3d,0xb7,0x5e,0x83,0x13,0x96,0xd3,0x09,0xec,0x53, - 0x25,0xd5,0x7e,0x0c,0xed,0xb9,0x58,0x34,0x02,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x40,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x2a,0x00,0x04,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x70,0x73,0x69,0x7a,0x65,0x00,0x03,0x80,0x56,0x41,0x54, - 0x59,0x06,0x00,0x04,0x00,0x06,0x04,0x06,0x03,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, - 0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00, - 0x00,0xc4,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00, - 0x00,0xee,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00, - 0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84, - 0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b, - 0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90, - 0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8, - 0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x81,0x00,0x00, - 0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77, - 0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8, - 0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87, - 0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c, - 0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8, - 0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18, - 0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc, - 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21, - 0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e, - 0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06, - 0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77, - 0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68, - 0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87, - 0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d, - 0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36, - 0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0, - 0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6, - 0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61, - 0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07, - 0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, - 0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e, - 0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea, - 0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c, - 0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea, - 0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1, - 0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x18,0x42, - 0x01,0x2c,0x40,0x05,0x00,0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40, - 0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, - 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, - 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00,0xc3,0x08,0x04,0x60,0x89,0x10,0x02, - 0x18,0x46,0x10,0x80,0x24,0x08,0x33,0x51,0xf3,0x40,0x0f,0xf2,0x50,0x0f,0xe3,0x40, - 0x0f,0x6e,0xd0,0x0e,0xe5,0x40,0x0f,0xe1,0xc0,0x0e,0x7a,0xa0,0x07,0xed,0x10,0x0e, - 0xf4,0x20,0x0f,0xe9,0x80,0x0f,0x28,0x20,0x07,0x49,0x53,0x44,0x09,0x93,0x5f,0x49, - 0xff,0x03,0x44,0x00,0x23,0x21,0xa1,0x94,0x41,0x04,0x43,0x28,0x86,0x08,0x23,0x80, - 0x43,0x68,0x20,0x60,0x8e,0x00,0x0c,0x52,0x60,0xcd,0x11,0x80,0xc2,0x20,0x42,0x20, - 0x0c,0x23,0x10,0xcb,0x08,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, - 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, - 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, - 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, - 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, - 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, - 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, - 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0xc8,0x02,0x01,0x00,0x00,0x0b,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18, - 0x50,0x08,0x65,0x50,0x80,0x02,0x05,0x51,0x20,0xd4,0x46,0x00,0x88,0x8d,0x25,0x34, - 0x01,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x02,0x01,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32, - 0x28,0x00,0xb3,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x2c,0x81,0x22,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25, - 0x58,0x90,0x45,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82, - 0x45,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04, - 0x65,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c, - 0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba, - 0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61, - 0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde, - 0xc2,0xe8,0x68,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95, - 0x51,0xa8,0xb3,0x1b,0xc2,0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9, - 0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0x61,0x31,0xf6,0xc6,0xf6,0x26, - 0x37,0x84,0x51,0x1e,0xc5,0x52,0x22,0x45,0x52,0x26,0xe5,0x22,0x13,0x96,0x26,0xe7, - 0x02,0xf7,0x36,0x97,0x46,0x97,0xf6,0xe6,0xc6,0xe5,0x8c,0xed,0x0b,0xea,0x6d,0x2e, - 0x8d,0x2e,0xed,0xcd,0x6d,0x88,0xa2,0x64,0x4a,0xa4,0x48,0xca,0xa4,0x68,0x74,0xc2, - 0xd2,0xe4,0x5c,0xe0,0xde,0xd2,0xdc,0xe8,0xbe,0xe6,0xd2,0xf4,0xca,0x58,0x98,0xb1, - 0xbd,0x85,0xd1,0x91,0x39,0x63,0xfb,0x82,0x7a,0x4b,0x73,0xa3,0x9b,0x4a,0xd3,0x2b, - 0x1b,0xa2,0x28,0x9c,0x12,0x29,0x9d,0x32,0x29,0xde,0x10,0x44,0xa9,0x14,0x4c,0xd9, - 0x94,0x8f,0x50,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0x57,0x9a,0x1b, - 0x5c,0x1d,0x1d,0xa5,0xb0,0x34,0x39,0x17,0xb6,0xb7,0xb1,0x30,0xba,0xb4,0x37,0xb7, - 0xaf,0x34,0x37,0xb2,0x32,0x3c,0x7a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64, - 0x28,0x5f,0x5f,0x61,0x69,0x72,0x5f,0x70,0x6c,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64, - 0x65,0x72,0x5f,0x5f,0x29,0x44,0xe0,0xde,0xe6,0xd2,0xe8,0xd2,0xde,0xdc,0x86,0x50, - 0x8b,0xa0,0x84,0x81,0x22,0x06,0x8b,0xb0,0x04,0xca,0x18,0x28,0x91,0x22,0x29,0x93, - 0x42,0x06,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x98,0xd0,0x95,0xe1,0x8d,0xbd,0xbd, - 0xc9,0x91,0xc1,0x0c,0xa1,0x96,0x40,0x09,0x03,0x45,0x0c,0x96,0x60,0x09,0x94,0x31, - 0x50,0x22,0xc5,0x0c,0x94,0x49,0x39,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43, - 0xa8,0x65,0x50,0xc2,0x40,0x11,0x83,0x65,0x58,0x02,0x65,0x0c,0x94,0x48,0x91,0x94, - 0x49,0x49,0x03,0x16,0x70,0x73,0x69,0x7a,0x65,0x43,0xa8,0xc5,0x50,0xc2,0x40,0x11, - 0x83,0xc5,0x58,0x02,0x65,0x0c,0x94,0x48,0xe9,0x94,0x49,0x59,0x03,0x2a,0x61,0x69, - 0x72,0x2e,0x62,0x75,0x66,0x66,0x65,0x72,0x7c,0xc2,0xd2,0xe4,0x5c,0xc4,0xea,0xcc, - 0xcc,0xca,0xe4,0xbe,0xe6,0xd2,0xf4,0xca,0x88,0x84,0xa5,0xc9,0xb9,0xc8,0x95,0x85, - 0x91,0x91,0x0a,0x4b,0x93,0x73,0x99,0xa3,0x93,0xab,0x1b,0xa3,0xfb,0xa2,0xcb,0x83, - 0x2b,0xfb,0x4a,0x73,0x33,0x7b,0x23,0x62,0xc6,0xf6,0x16,0x46,0x47,0x83,0x47,0xc3, - 0xa1,0xcd,0x0e,0x8e,0x02,0x5d,0xdb,0x10,0x6a,0x11,0x16,0x62,0x11,0x94,0x38,0x50, - 0xe4,0x60,0x21,0x16,0x62,0x11,0x94,0x38,0x50,0xe6,0x80,0x51,0x58,0x9a,0x9c,0x4b, - 0x98,0xdc,0xd9,0x17,0x5d,0x1e,0x5c,0xd9,0xd7,0x5c,0x9a,0x5e,0x19,0xaf,0xb0,0x34, - 0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x30,0xb6,0xb4,0x33,0xb7, - 0xaf,0xb9,0x34,0xbd,0x32,0x26,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x1c, - 0xbe,0x62,0x72,0x86,0x90,0xc1,0x52,0x28,0x6d,0xa0,0xb8,0xc1,0x72,0x28,0x62,0xb0, - 0x08,0x4b,0xa0,0xbc,0x81,0x02,0x07,0x0a,0x1d,0x28,0x75,0xb0,0x1c,0x8a,0x1d,0x2c, - 0x89,0x12,0x29,0x77,0xa0,0x4c,0x0a,0x1e,0x0c,0x51,0x94,0x32,0x50,0xd0,0x40,0x51, - 0x03,0x85,0x0d,0x94,0x3c,0x18,0x62,0x24,0x80,0x02,0x06,0x8a,0x1e,0xf0,0x79,0x6b, - 0x73,0x4b,0x83,0x7b,0xa3,0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3,0x33,0x95, - 0xd6,0x06,0xc7,0x56,0x06,0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34,0x44,0x50, - 0xfa,0x60,0x88,0xa1,0xf0,0x81,0xe2,0x07,0x8d,0x32,0xc4,0x50,0xfe,0x40,0xf9,0x83, - 0x46,0x19,0x11,0xb1,0x03,0x3b,0xd8,0x43,0x3b,0xb8,0x41,0x3b,0xbc,0x03,0x39,0xd4, - 0x03,0x3b,0x94,0x83,0x1b,0x98,0x03,0x3b,0x84,0xc3,0x39,0xcc,0xc3,0x14,0x21,0x18, - 0x46,0x28,0xec,0xc0,0x0e,0xf6,0xd0,0x0e,0x6e,0x90,0x0e,0xe4,0x50,0x0e,0xee,0x40, - 0x0f,0x53,0x82,0x62,0xc4,0x12,0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f, - 0xf3,0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02,0x63,0x04,0x15,0x0e,0xe9,0x20,0x0f,0x6e, - 0xc0,0x0e,0xe1,0xe0,0x0e,0xe7,0x50,0x0f,0xe1,0x70,0x0e,0xe5,0xf0,0x0b,0xf6,0x50, - 0x0e,0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25,0x40,0x46,0x4c,0xe1,0x90,0x0e, - 0xf2,0xe0,0x06,0xe3,0xf0,0x0e,0xed,0x00,0x0f,0xe9,0xc0,0x0e,0xe5,0xf0,0x0b,0xef, - 0x00,0x0f,0xf4,0x90,0x0e,0xef,0xe0,0x0e,0xf3,0x30,0x65,0x50,0x18,0x67,0x84,0x12, - 0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f,0xf4,0x50,0x0e,0xf8,0x30,0x25, - 0xd8,0x03,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80, - 0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80, - 0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80, - 0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88, - 0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78, - 0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03, - 0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f, - 0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c, - 0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39, - 0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60, - 0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87, - 0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e, - 0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c, - 0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6, - 0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94, - 0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03, - 0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07, - 0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f, - 0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33, - 0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc, - 0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c, - 0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78, - 0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca, - 0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21, - 0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43, - 0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87, - 0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c, - 0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e, - 0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c, - 0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c, - 0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00, - 0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x3e,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0xf4,0xc6,0x22, - 0x86,0x61,0x18,0xc6,0x22,0x04,0x41,0x10,0xc6,0x22,0x82,0x20,0x08,0xa8,0x95,0x40, - 0x19,0x14,0x01,0xbd,0x11,0x00,0x1a,0x33,0x00,0x24,0x66,0x00,0x28,0xcc,0x00,0x00, - 0x00,0xe3,0x15,0x4b,0x94,0x65,0x11,0x05,0x65,0x90,0x21,0x1a,0x0c,0x13,0x02,0xf9, - 0x8c,0x57,0x3c,0x55,0xd7,0x2d,0x14,0x94,0x41,0x86,0xea,0x70,0x4c,0x08,0xe4,0x63, - 0x41,0x01,0x9f,0xf1,0x0a,0x4a,0x13,0x03,0x31,0x70,0x28,0x28,0x83,0x0c,0x1a,0x43, - 0x99,0x10,0xc8,0xc7,0x8a,0x00,0x3e,0xe3,0x15,0xd9,0x77,0x06,0x67,0x40,0x51,0x50, - 0x06,0x19,0xbe,0x48,0x33,0x21,0x90,0x8f,0x15,0x01,0x7c,0xc6,0x2b,0x3c,0x32,0x68, - 0x03,0x36,0x20,0x03,0x0a,0xca,0x20,0xc3,0x18,0x60,0x99,0x09,0x81,0x7c,0xc6,0x2b, - 0xc4,0x00,0x0d,0xe2,0x00,0x0e,0x3c,0x0a,0xca,0x20,0xc3,0x19,0x70,0x61,0x60,0x42, - 0x20,0x1f,0x0b,0x0a,0xf8,0x8c,0x57,0x9c,0x41,0x1b,0xd8,0x41,0x1d,0x88,0x01,0x05, - 0xc5,0x86,0x00,0x3e,0xb3,0x0d,0x61,0x10,0x00,0xb3,0x0d,0x41,0x1b,0x04,0xb3,0x0d, - 0xc1,0x23,0xcc,0x36,0x04,0x6e,0x30,0x64,0x10,0x10,0x03,0x00,0x00,0x09,0x00,0x00, - 0x00,0x5b,0x86,0x20,0x00,0x85,0x2d,0x43,0x11,0x80,0xc2,0x96,0x41,0x09,0x40,0x61, - 0xcb,0xf0,0x04,0xa0,0xb0,0x65,0xa0,0x02,0x50,0xd8,0x32,0x60,0x01,0x28,0x6c,0x19, - 0xba,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sgl_fs_bytecode_metal_macos[2825] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x09,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x30,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xb9,0x65,0x80,0x88,0xa2,0xc8,0x18, - 0x8d,0x2a,0x38,0xc1,0x87,0xa4,0x7f,0x35,0x83,0x69,0xdc,0x8c,0xcb,0x7b,0x11,0x67, - 0x89,0xc7,0xf0,0x8a,0x99,0x36,0x06,0xc5,0x90,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x10,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x81,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x70,0x94,0x34,0x45,0x94,0x30, - 0xf9,0xff,0x44,0x5c,0x13,0x15,0x11,0xbf,0x3d,0xfc,0xd3,0x18,0x01,0x30,0x88,0x30, - 0x04,0x17,0x49,0x53,0x44,0x09,0x93,0xff,0x4b,0x00,0xf3,0x2c,0x44,0xf4,0x4f,0x63, - 0x04,0xc0,0x20,0x42,0x21,0x94,0x42,0x84,0x40,0x0c,0x9d,0x61,0x04,0x01,0x98,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0x88,0x49,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, - 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, - 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, - 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, - 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, - 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, - 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, - 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x41,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64,0x81,0x00,0x00,0x00, - 0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, - 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70, - 0x2c,0xa1,0x09,0x00,0x00,0x79,0x18,0x00,0x00,0xb7,0x00,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42, - 0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45, - 0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84, - 0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84, - 0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c, - 0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0, - 0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32, - 0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe, - 0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d, - 0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08,0x0f,0x45,0x29,0x2c, - 0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e, - 0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34, - 0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72, - 0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x14,0xea,0xec,0x86,0x48,0xcb,0xf0,0x58, - 0xcf,0xf5,0x60,0x4f,0xf6,0x40,0x4f,0xf4,0x48,0x8f,0xc6,0xa5,0x6e,0xae,0x4c,0x0e, - 0x85,0xed,0x6d,0xcc,0x2d,0x26,0x85,0xc5,0xd8,0x1b,0xdb,0x9b,0xdc,0x10,0x69,0x11, - 0x1e,0xeb,0xe1,0x1e,0xec,0xc9,0x1e,0xe8,0x89,0x1e,0xe9,0xe9,0xb8,0x84,0xa5,0xc9, - 0xb9,0xd0,0x95,0xe1,0xd1,0xd5,0xc9,0x95,0x51,0x0a,0x4b,0x93,0x73,0x61,0x7b,0x1b, - 0x0b,0xa3,0x4b,0x7b,0x73,0xfb,0x4a,0x73,0x23,0x2b,0xc3,0xa3,0x12,0x96,0x26,0xe7, - 0x32,0x17,0xd6,0x06,0xc7,0x56,0x46,0x8c,0xae,0x0c,0x8f,0xae,0x4e,0xae,0x4c,0x86, - 0x8c,0xc7,0x8c,0xed,0x2d,0x8c,0x8e,0x05,0x64,0x2e,0xac,0x0d,0x8e,0xad,0xcc,0x87, - 0x03,0x5d,0x19,0xde,0x10,0x6a,0x21,0x9e,0xef,0x01,0x83,0x65,0x58,0x84,0x27,0x0c, - 0x1e,0xe8,0x11,0x83,0x47,0x7a,0xc6,0x80,0x4b,0x58,0x9a,0x9c,0xcb,0x5c,0x58,0x1b, - 0x1c,0x5b,0x99,0x1c,0x8f,0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39,0x0e,0x73,0x6d,0x70, - 0x43,0xa4,0xe5,0x78,0xca,0xe0,0x01,0x83,0x65,0x58,0x84,0x07,0x7a,0xcc,0xe0,0x91, - 0x9e,0x33,0x18,0x82,0x3c,0xdb,0xe3,0x3d,0x64,0xf0,0xa0,0xc1,0x10,0x03,0x01,0x9e, - 0xea,0x49,0x83,0x11,0x11,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b,0xb4,0xc3,0x3b,0x90, - 0x43,0x3d,0xb0,0x43,0x39,0xb8,0x81,0x39,0xb0,0x43,0x38,0x9c,0xc3,0x3c,0x4c,0x11, - 0x82,0x61,0x84,0xc2,0x0e,0xec,0x60,0x0f,0xed,0xe0,0x06,0xe9,0x40,0x0e,0xe5,0xe0, - 0x0e,0xf4,0x30,0x25,0x28,0x46,0x2c,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xf6,0x50,0x0e, - 0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25,0x30,0x46,0x50,0xe1,0x90,0x0e,0xf2, - 0xe0,0x06,0xec,0x10,0x0e,0xee,0x70,0x0e,0xf5,0x10,0x0e,0xe7,0x50,0x0e,0xbf,0x60, - 0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0,0x0e,0x53,0x02,0x64,0xc4,0x14,0x0e, - 0xe9,0x20,0x0f,0x6e,0x30,0x0e,0xef,0xd0,0x0e,0xf0,0x90,0x0e,0xec,0x50,0x0e,0xbf, - 0xf0,0x0e,0xf0,0x40,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x0f,0x53,0x06,0x85,0x71,0x46, - 0x30,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe6,0x20,0x0f,0xe1,0x70,0x0e,0xed,0x50,0x0e, - 0xee,0x40,0x0f,0x53,0x02,0x35,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00, - 0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84, - 0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed, - 0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66, - 0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c, - 0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70, - 0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90, - 0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4, - 0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83, - 0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14, - 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70, - 0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80, - 0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0, - 0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1, - 0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d, - 0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39, - 0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc, - 0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70, - 0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53, - 0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e, - 0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c, - 0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38, - 0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37, - 0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33, - 0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4, - 0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0, - 0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3, - 0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07, - 0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23, - 0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59, - 0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b, - 0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00, - 0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f, - 0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20, - 0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x0f,0x00,0x00,0x00,0x13,0x04,0x41, - 0x2c,0x10,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0xc4,0x46,0x00,0xc6,0x12,0x80,0x80, - 0xd4,0x08,0x40,0x0d,0x90,0x98,0x01,0xa0,0x30,0x03,0x40,0x60,0x04,0x00,0x00,0x00, - 0x00,0x83,0x0c,0x8b,0x60,0x8c,0x18,0x28,0x42,0x40,0x29,0x49,0x50,0x20,0x86,0x60, - 0x01,0x23,0x9f,0xd9,0x06,0x23,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sgl_vs_bytecode_metal_ios[3317] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf5,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x17,0x11,0x57,0x16,0x94,0x42,0x52, - 0xfb,0x1e,0xd0,0x32,0xfd,0x87,0x16,0xb0,0xa4,0xd0,0xc2,0x43,0xbe,0x93,0x8c,0xe0, - 0x2d,0x7a,0x5c,0x3e,0x06,0x4c,0x57,0xeb,0x4b,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x40,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x2a,0x00,0x04,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x70,0x73,0x69,0x7a,0x65,0x00,0x03,0x80,0x56,0x41,0x54, - 0x59,0x06,0x00,0x04,0x00,0x06,0x04,0x06,0x03,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, - 0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00, - 0x00,0xc0,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00, - 0x00,0xed,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00, - 0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84, - 0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b, - 0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90, - 0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8, - 0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x82,0x00,0x00, - 0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77, - 0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8, - 0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87, - 0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c, - 0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8, - 0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18, - 0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc, - 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21, - 0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e, - 0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06, - 0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77, - 0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68, - 0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87, - 0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76, - 0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d, - 0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36, - 0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0, - 0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6, - 0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61, - 0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07, - 0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, - 0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e, - 0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea, - 0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c, - 0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea, - 0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1, - 0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x20,0x42, - 0x01,0x24,0xc0,0x02,0x54,0x00,0x00,0x00,0x00,0x49,0x18,0x00,0x00,0x01,0x00,0x00, - 0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48, - 0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90, - 0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00,0xc3,0x08,0x04, - 0x60,0x89,0x10,0x02,0x18,0x46,0x10,0x80,0x24,0x08,0x33,0x51,0xf3,0x40,0x0f,0xf2, - 0x50,0x0f,0xe3,0x40,0x0f,0x6e,0xd0,0x0e,0xe5,0x40,0x0f,0xe1,0xc0,0x0e,0x7a,0xa0, - 0x07,0xed,0x10,0x0e,0xf4,0x20,0x0f,0xe9,0x80,0x0f,0x28,0x20,0x07,0x49,0x53,0x44, - 0x09,0x93,0x5f,0x49,0xff,0x03,0x44,0x00,0x23,0x21,0xa1,0x94,0x41,0x04,0x43,0x28, - 0x86,0x08,0x23,0x80,0x43,0x68,0x20,0x60,0x8e,0x00,0x0c,0x52,0x60,0xcd,0x11,0x80, - 0xc2,0x20,0x42,0x20,0x0c,0x23,0x10,0xcb,0x08,0x00,0x00,0x00,0x00,0x13,0xa8,0x70, - 0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68, - 0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51, - 0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78, - 0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0, - 0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90, - 0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06, - 0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72, - 0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10, - 0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07, - 0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73, - 0x20,0x07,0x43,0x98,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x2c,0x10,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, - 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18,0x50,0x08,0x65,0x50, - 0x80,0x02,0x05,0x51,0x20,0xd4,0x46,0x00,0x88,0x8d,0x25,0x40,0x02,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x02,0x01,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2, - 0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32,0x28,0x00,0xb3,0x50, - 0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0x81,0x22,0x2c, - 0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae, - 0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06, - 0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25,0x58,0x90,0x45,0x60, - 0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82,0x45,0xe0,0x16,0x96, - 0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7, - 0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50,0x12,0x72,0x61,0x69, - 0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d, - 0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x65,0x21,0x19,0x84, - 0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95, - 0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85, - 0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d, - 0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6, - 0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79, - 0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x68,0xc8,0x84, - 0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2, - 0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61, - 0x7b,0x1b,0x73,0x8b,0x49,0x61,0x31,0xf6,0xc6,0xf6,0x26,0x37,0x84,0x51,0x1e,0xc5, - 0x52,0x22,0x45,0x52,0x26,0xe5,0x22,0x13,0x96,0x26,0xe7,0x02,0xf7,0x36,0x97,0x46, - 0x97,0xf6,0xe6,0xc6,0xe5,0x8c,0xed,0x0b,0xea,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x6d, - 0x88,0xa2,0x64,0x4a,0xa4,0x48,0xca,0xa4,0x68,0x74,0xc2,0xd2,0xe4,0x5c,0xe0,0xde, - 0xd2,0xdc,0xe8,0xbe,0xe6,0xd2,0xf4,0xca,0x58,0x98,0xb1,0xbd,0x85,0xd1,0x91,0x39, - 0x63,0xfb,0x82,0x7a,0x4b,0x73,0xa3,0x9b,0x4a,0xd3,0x2b,0x1b,0xa2,0x28,0x9c,0x12, - 0x29,0x9d,0x32,0x29,0xde,0x10,0x44,0xa9,0x14,0x4c,0xd9,0x94,0x8f,0x50,0x58,0x9a, - 0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0x57,0x9a,0x1b,0x5c,0x1d,0x1d,0xa5,0xb0, - 0x34,0x39,0x17,0xb6,0xb7,0xb1,0x30,0xba,0xb4,0x37,0xb7,0xaf,0x34,0x37,0xb2,0x32, - 0x3c,0x7a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64,0x28,0x5f,0x5f,0x61,0x69, - 0x72,0x5f,0x70,0x6c,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64,0x65,0x72,0x5f,0x5f,0x29, - 0x44,0xe0,0xde,0xe6,0xd2,0xe8,0xd2,0xde,0xdc,0x86,0x50,0x8b,0xa0,0x84,0x81,0x22, - 0x06,0x8b,0xb0,0x04,0xca,0x18,0x28,0x91,0x22,0x29,0x93,0x42,0x06,0x34,0xcc,0xd8, - 0xde,0xc2,0xe8,0x64,0x98,0xd0,0x95,0xe1,0x8d,0xbd,0xbd,0xc9,0x91,0xc1,0x0c,0xa1, - 0x96,0x40,0x09,0x03,0x45,0x0c,0x96,0x60,0x09,0x94,0x31,0x50,0x22,0xc5,0x0c,0x94, - 0x49,0x39,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x65,0x50,0xc2,0x40, - 0x11,0x83,0x65,0x58,0x02,0x65,0x0c,0x94,0x48,0x91,0x94,0x49,0x49,0x03,0x16,0x70, - 0x73,0x69,0x7a,0x65,0x43,0xa8,0xc5,0x50,0xc2,0x40,0x11,0x83,0xc5,0x58,0x02,0x65, - 0x0c,0x94,0x48,0xe9,0x94,0x49,0x59,0x03,0x2a,0x61,0x69,0x72,0x2e,0x62,0x75,0x66, - 0x66,0x65,0x72,0x7c,0xc2,0xd2,0xe4,0x5c,0xc4,0xea,0xcc,0xcc,0xca,0xe4,0xbe,0xe6, - 0xd2,0xf4,0xca,0x88,0x84,0xa5,0xc9,0xb9,0xc8,0x95,0x85,0x91,0x91,0x0a,0x4b,0x93, - 0x73,0x99,0xa3,0x93,0xab,0x1b,0xa3,0xfb,0xa2,0xcb,0x83,0x2b,0xfb,0x4a,0x73,0x33, - 0x7b,0x23,0x62,0xc6,0xf6,0x16,0x46,0x47,0x83,0x47,0xc3,0xa1,0xcd,0x0e,0x8e,0x02, - 0x5d,0xdb,0x10,0x6a,0x11,0x16,0x62,0x11,0x94,0x38,0x50,0xe4,0x60,0x21,0x16,0x62, - 0x11,0x94,0x38,0x50,0xe6,0x80,0x51,0x58,0x9a,0x9c,0x4b,0x98,0xdc,0xd9,0x17,0x5d, - 0x1e,0x5c,0xd9,0xd7,0x5c,0x9a,0x5e,0x19,0xaf,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3, - 0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x30,0xb6,0xb4,0x33,0xb7,0xaf,0xb9,0x34,0xbd,0x32, - 0x26,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x1c,0xbe,0x62,0x72,0x86,0x90, - 0xc1,0x52,0x28,0x6d,0xa0,0xb8,0xc1,0x72,0x28,0x62,0xb0,0x08,0x4b,0xa0,0xbc,0x81, - 0x02,0x07,0x0a,0x1d,0x28,0x75,0xb0,0x1c,0x8a,0x1d,0x2c,0x89,0x12,0x29,0x77,0xa0, - 0x4c,0x0a,0x1e,0x0c,0x51,0x94,0x32,0x50,0xd0,0x40,0x51,0x03,0x85,0x0d,0x94,0x3c, - 0x18,0x62,0x24,0x80,0x02,0x06,0x8a,0x1e,0xf0,0x79,0x6b,0x73,0x4b,0x83,0x7b,0xa3, - 0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3,0x33,0x95,0xd6,0x06,0xc7,0x56,0x06, - 0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34,0x44,0x50,0xfa,0x60,0x88,0xa1,0xf0, - 0x81,0xe2,0x07,0x8d,0x32,0xc4,0x50,0xfe,0x40,0xf9,0x83,0x46,0x19,0x11,0xb1,0x03, - 0x3b,0xd8,0x43,0x3b,0xb8,0x41,0x3b,0xbc,0x03,0x39,0xd4,0x03,0x3b,0x94,0x83,0x1b, - 0x98,0x03,0x3b,0x84,0xc3,0x39,0xcc,0xc3,0x14,0x21,0x18,0x46,0x28,0xec,0xc0,0x0e, - 0xf6,0xd0,0x0e,0x6e,0x90,0x0e,0xe4,0x50,0x0e,0xee,0x40,0x0f,0x53,0x82,0x62,0xc4, - 0x12,0x0e,0xe9,0x20,0x0f,0x6e,0x60,0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0, - 0x0e,0x53,0x02,0x63,0x04,0x15,0x0e,0xe9,0x20,0x0f,0x6e,0xc0,0x0e,0xe1,0xe0,0x0e, - 0xe7,0x50,0x0f,0xe1,0x70,0x0e,0xe5,0xf0,0x0b,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9, - 0xf0,0x0e,0xee,0x30,0x25,0x40,0x46,0x4c,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe3,0xf0, - 0x0e,0xed,0x00,0x0f,0xe9,0xc0,0x0e,0xe5,0xf0,0x0b,0xef,0x00,0x0f,0xf4,0x90,0x0e, - 0xef,0xe0,0x0e,0xf3,0x30,0x65,0x50,0x18,0x67,0x84,0x12,0x0e,0xe9,0x20,0x0f,0x6e, - 0x60,0x0f,0xe5,0x20,0x0f,0xf4,0x50,0x0e,0xf8,0x30,0x25,0xd8,0x03,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30, - 0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x3e,0x00,0x00,0x00,0x13,0x04,0x41, - 0x2c,0x10,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0xf4,0xc6,0x22,0x86,0x61,0x18,0xc6, - 0x22,0x04,0x41,0x10,0xc6,0x22,0x82,0x20,0x08,0xa8,0x95,0x40,0x19,0x14,0x01,0xbd, - 0x11,0x00,0x1a,0x33,0x00,0x24,0x66,0x00,0x28,0xcc,0x00,0x00,0x00,0xe3,0x15,0x4b, - 0x94,0x65,0x11,0x05,0x65,0x90,0x21,0x1a,0x0c,0x13,0x02,0xf9,0x8c,0x57,0x3c,0x55, - 0xd7,0x2d,0x14,0x94,0x41,0x86,0xea,0x70,0x4c,0x08,0xe4,0x63,0x41,0x01,0x9f,0xf1, - 0x0a,0x4a,0x13,0x03,0x31,0x70,0x28,0x28,0x83,0x0c,0x1a,0x43,0x99,0x10,0xc8,0xc7, - 0x8a,0x00,0x3e,0xe3,0x15,0xd9,0x77,0x06,0x67,0x40,0x51,0x50,0x06,0x19,0xbe,0x48, - 0x33,0x21,0x90,0x8f,0x15,0x01,0x7c,0xc6,0x2b,0x3c,0x32,0x68,0x03,0x36,0x20,0x03, - 0x0a,0xca,0x20,0xc3,0x18,0x60,0x99,0x09,0x81,0x7c,0xc6,0x2b,0xc4,0x00,0x0d,0xe2, - 0x00,0x0e,0x3c,0x0a,0xca,0x20,0xc3,0x19,0x70,0x61,0x60,0x42,0x20,0x1f,0x0b,0x0a, - 0xf8,0x8c,0x57,0x9c,0x41,0x1b,0xd8,0x41,0x1d,0x88,0x01,0x05,0xc5,0x86,0x00,0x3e, - 0xb3,0x0d,0x61,0x10,0x00,0xb3,0x0d,0x41,0x1b,0x04,0xb3,0x0d,0xc1,0x23,0xcc,0x36, - 0x04,0x6e,0x30,0x64,0x10,0x10,0x03,0x00,0x00,0x09,0x00,0x00,0x00,0x5b,0x86,0x20, - 0x00,0x85,0x2d,0x43,0x11,0x80,0xc2,0x96,0x41,0x09,0x40,0x61,0xcb,0xf0,0x04,0xa0, - 0xb0,0x65,0xa0,0x02,0x50,0xd8,0x32,0x60,0x01,0x28,0x6c,0x19,0xba,0x00,0x14,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sgl_fs_bytecode_metal_ios[2809] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf9,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x20,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xc1,0x98,0x28,0x2b,0x2b,0x1f,0x36, - 0x7c,0x5c,0xb0,0x69,0x3f,0xc3,0xd1,0x80,0x4b,0xcf,0xa1,0x10,0xfc,0x19,0x31,0x58, - 0xad,0x45,0xd3,0x5a,0x81,0x72,0x0d,0x8f,0x85,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x08,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x7f,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x70,0x94,0x34,0x45,0x94,0x30, - 0xf9,0xff,0x44,0x5c,0x13,0x15,0x11,0xbf,0x3d,0xfc,0xd3,0x18,0x01,0x30,0x88,0x30, - 0x04,0x17,0x49,0x53,0x44,0x09,0x93,0xff,0x4b,0x00,0xf3,0x2c,0x44,0xf4,0x4f,0x63, - 0x04,0xc0,0x20,0x42,0x21,0x94,0x42,0x84,0x40,0x0c,0x9d,0x61,0x04,0x01,0x98,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0x88,0x49,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xa8,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x74,0x78,0x87, - 0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9, - 0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0, - 0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07, - 0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0, - 0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xf6,0x20, - 0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x40,0x07,0x78, - 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07,0x76,0xa0,0x07, - 0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x72, - 0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60, - 0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07, - 0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a, - 0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10, - 0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07,0x70,0x20,0x07, - 0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20,0x07,0x43,0x18, - 0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03,0x04,0x80,0x00,0x00, - 0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98, - 0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02, - 0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0x01,0x12,0x00,0x00,0x79,0x18,0x00, - 0x00,0xb7,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32, - 0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b, - 0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08, - 0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed, - 0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c, - 0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45, - 0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17, - 0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6, - 0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96, - 0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f, - 0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c, - 0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99, - 0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d, - 0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d, - 0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c, - 0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2, - 0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d, - 0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9, - 0x99,0x86,0x08,0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc, - 0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb, - 0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e, - 0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x14, - 0xea,0xec,0x86,0x48,0xcb,0xf0,0x58,0xcf,0xf5,0x60,0x4f,0xf6,0x40,0x4f,0xf4,0x48, - 0x8f,0xc6,0xa5,0x6e,0xae,0x4c,0x0e,0x85,0xed,0x6d,0xcc,0x2d,0x26,0x85,0xc5,0xd8, - 0x1b,0xdb,0x9b,0xdc,0x10,0x69,0x11,0x1e,0xeb,0xe1,0x1e,0xec,0xc9,0x1e,0xe8,0x89, - 0x1e,0xe9,0xe9,0xb8,0x84,0xa5,0xc9,0xb9,0xd0,0x95,0xe1,0xd1,0xd5,0xc9,0x95,0x51, - 0x0a,0x4b,0x93,0x73,0x61,0x7b,0x1b,0x0b,0xa3,0x4b,0x7b,0x73,0xfb,0x4a,0x73,0x23, - 0x2b,0xc3,0xa3,0x12,0x96,0x26,0xe7,0x32,0x17,0xd6,0x06,0xc7,0x56,0x46,0x8c,0xae, - 0x0c,0x8f,0xae,0x4e,0xae,0x4c,0x86,0x8c,0xc7,0x8c,0xed,0x2d,0x8c,0x8e,0x05,0x64, - 0x2e,0xac,0x0d,0x8e,0xad,0xcc,0x87,0x03,0x5d,0x19,0xde,0x10,0x6a,0x21,0x9e,0xef, - 0x01,0x83,0x65,0x58,0x84,0x27,0x0c,0x1e,0xe8,0x11,0x83,0x47,0x7a,0xc6,0x80,0x4b, - 0x58,0x9a,0x9c,0xcb,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x8f,0xb9,0xb0,0x36,0x38, - 0xb6,0x32,0x39,0x0e,0x73,0x6d,0x70,0x43,0xa4,0xe5,0x78,0xca,0xe0,0x01,0x83,0x65, - 0x58,0x84,0x07,0x7a,0xcc,0xe0,0x91,0x9e,0x33,0x18,0x82,0x3c,0xdb,0xe3,0x3d,0x64, - 0xf0,0xa0,0xc1,0x10,0x03,0x01,0x9e,0xea,0x49,0x83,0x11,0x11,0x3b,0xb0,0x83,0x3d, - 0xb4,0x83,0x1b,0xb4,0xc3,0x3b,0x90,0x43,0x3d,0xb0,0x43,0x39,0xb8,0x81,0x39,0xb0, - 0x43,0x38,0x9c,0xc3,0x3c,0x4c,0x11,0x82,0x61,0x84,0xc2,0x0e,0xec,0x60,0x0f,0xed, - 0xe0,0x06,0xe9,0x40,0x0e,0xe5,0xe0,0x0e,0xf4,0x30,0x25,0x28,0x46,0x2c,0xe1,0x90, - 0x0e,0xf2,0xe0,0x06,0xf6,0x50,0x0e,0xf2,0x30,0x0f,0xe9,0xf0,0x0e,0xee,0x30,0x25, - 0x30,0x46,0x50,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xec,0x10,0x0e,0xee,0x70,0x0e,0xf5, - 0x10,0x0e,0xe7,0x50,0x0e,0xbf,0x60,0x0f,0xe5,0x20,0x0f,0xf3,0x90,0x0e,0xef,0xe0, - 0x0e,0x53,0x02,0x64,0xc4,0x14,0x0e,0xe9,0x20,0x0f,0x6e,0x30,0x0e,0xef,0xd0,0x0e, - 0xf0,0x90,0x0e,0xec,0x50,0x0e,0xbf,0xf0,0x0e,0xf0,0x40,0x0f,0xe9,0xf0,0x0e,0xee, - 0x30,0x0f,0x53,0x06,0x85,0x71,0x46,0x30,0xe1,0x90,0x0e,0xf2,0xe0,0x06,0xe6,0x20, - 0x0f,0xe1,0x70,0x0e,0xed,0x50,0x0e,0xee,0x40,0x0f,0x53,0x02,0x35,0x00,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01, - 0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e, - 0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00, - 0x00,0x0f,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x06,0x00,0x00, - 0x00,0xc4,0x46,0x00,0xc6,0x12,0x80,0x80,0xd4,0x08,0x40,0x0d,0x90,0x98,0x01,0xa0, - 0x30,0x03,0x40,0x60,0x04,0x00,0x00,0x00,0x00,0x83,0x0c,0x8b,0x60,0x8c,0x18,0x28, - 0x42,0x40,0x29,0x49,0x50,0x20,0x86,0x60,0x01,0x23,0x9f,0xd9,0x06,0x23,0x00,0x32, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sgl_vs_source_metal_sim[756] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x6d,0x76,0x70,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x74,0x6d,0x3b,0x0a,0x7d,0x3b, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, - 0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, - 0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a, - 0x65,0x20,0x5b,0x5b,0x70,0x6f,0x69,0x6e,0x74,0x5f,0x73,0x69,0x7a,0x65,0x5d,0x5d, - 0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, - 0x74,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74, - 0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72, - 0x64,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31, - 0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75, - 0x74,0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x20,0x70,0x73,0x69,0x7a,0x65,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69, - 0x62,0x75,0x74,0x65,0x28,0x33,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76, - 0x65,0x72,0x74,0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20, - 0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69, - 0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20, - 0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x26,0x20,0x5f,0x31,0x39,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72, - 0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70,0x20,0x2a, - 0x20,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69, - 0x7a,0x65,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20, - 0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75,0x76,0x20,0x3d,0x20,0x5f,0x31,0x39,0x2e, - 0x74,0x6d,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31, - 0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sgl_fs_source_metal_sim[439] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65, - 0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65, - 0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d, - 0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b, - 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, - 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, - 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e, - 0x75,0x76,0x2e,0x78,0x79,0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f, - 0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75, - 0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _sgl_vs_bytecode_hlsl4[1032] = { - 0x44,0x58,0x42,0x43,0x74,0x7f,0x01,0xd9,0xf4,0xd5,0xed,0x1d,0x74,0xc1,0x30,0x27, - 0xd8,0xe9,0x9d,0x50,0x01,0x00,0x00,0x00,0x08,0x04,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x90,0x01,0x00,0x00,0x00,0x02,0x00,0x00, - 0x8c,0x03,0x00,0x00,0x52,0x44,0x45,0x46,0xd8,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0xaf,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x60,0x00,0x00,0x00, - 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x98,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f, - 0x6d,0x76,0x70,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f,0x74,0x6d,0x00,0x4d,0x69,0x63,0x72,0x6f, - 0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68, - 0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30, - 0x2e,0x31,0x00,0xab,0x49,0x53,0x47,0x4e,0x74,0x00,0x00,0x00,0x04,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x68,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x68,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x68,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab, - 0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab, - 0x53,0x48,0x44,0x52,0x84,0x01,0x00,0x00,0x40,0x00,0x01,0x00,0x61,0x00,0x00,0x00, - 0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, - 0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00, - 0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04, - 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02, - 0x01,0x00,0x00,0x00,0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x56,0x15,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x06,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x04,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x36,0x00,0x00,0x05, - 0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00, - 0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x56,0x15,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0xa6,0x1a,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x32,0x00,0x00,0x0a,0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0xf6,0x1f,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54, - 0x74,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sgl_fs_bytecode_hlsl4[608] = { - 0x44,0x58,0x42,0x43,0xc8,0x9b,0x66,0x64,0x80,0x2f,0xbe,0x14,0xd9,0x88,0xa0,0x97, - 0x64,0x14,0x66,0xff,0x01,0x00,0x00,0x00,0x60,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x48,0x01,0x00,0x00, - 0xe4,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0x64,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c, - 0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x03,0x00,0x00, - 0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54, - 0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0x94,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00, - 0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00, - 0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00, - 0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - -}; -#elif defined(SOKOL_WGPU) -static const uint8_t _sgl_vs_source_wgsl[1162] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x6d,0x76,0x70,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78,0x34,0x66,0x2c,0x0a, - 0x20,0x20,0x2f,0x2a,0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x36,0x34,0x29, - 0x20,0x2a,0x2f,0x0a,0x20,0x20,0x74,0x6d,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78, - 0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x30,0x29, - 0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20,0x76,0x61,0x72, - 0x3c,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x31,0x39,0x20,0x3a, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x76,0x61,0x72, - 0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76, - 0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72, - 0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x70,0x73,0x69,0x7a,0x65,0x20,0x3a,0x20,0x66,0x33,0x32,0x3b,0x0a,0x0a, - 0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b, - 0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x32,0x20,0x3a,0x20,0x6d,0x61, - 0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x6d,0x76,0x70, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x35,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f, - 0x31,0x3b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x32,0x20,0x2a,0x20,0x78,0x5f,0x32,0x35,0x29, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x32,0x20,0x3a,0x20,0x6d, - 0x61,0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x74,0x6d, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x36,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30, - 0x3b,0x0a,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x28,0x78,0x5f,0x33,0x32,0x20,0x2a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x33,0x36,0x2e,0x78,0x2c,0x20,0x78, - 0x5f,0x33,0x36,0x2e,0x79,0x2c,0x20,0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30, - 0x66,0x29,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x35,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x78,0x5f,0x34,0x35, - 0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73, - 0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b, - 0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c,0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x0a,0x20,0x20,0x75,0x76, - 0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a, - 0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x32,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c, - 0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x33,0x29,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x66,0x33,0x32,0x29, - 0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20, - 0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x3d,0x20,0x74,0x65, - 0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x70,0x73,0x69,0x7a,0x65,0x20, - 0x3d,0x20,0x70,0x73,0x69,0x7a,0x65,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74, - 0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sgl_fs_source_wgsl[647] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x34,0x38, - 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, - 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x36,0x34,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x35,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x78,0x5f,0x32,0x33,0x2e,0x78, - 0x2c,0x20,0x78,0x5f,0x32,0x33,0x2e,0x79,0x29,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x32,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x35,0x20,0x2a,0x20,0x78, - 0x5f,0x32,0x37,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f, - 0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x28,0x30,0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40, - 0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b, - 0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31, - 0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69, - 0x6e,0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _sgl_vs_source_dummy = ""; -static const char* _sgl_fs_source_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -// ████████ ██ ██ ██████ ███████ ███████ -// ██ ██ ██ ██ ██ ██ ██ -// ██ ████ ██████ █████ ███████ -// ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ███████ -// -// >>types -typedef enum { - SGL_PRIMITIVETYPE_POINTS = 0, - SGL_PRIMITIVETYPE_LINES, - SGL_PRIMITIVETYPE_LINE_STRIP, - SGL_PRIMITIVETYPE_TRIANGLES, - SGL_PRIMITIVETYPE_TRIANGLE_STRIP, - SGL_PRIMITIVETYPE_QUADS, - SGL_NUM_PRIMITIVE_TYPES, -} _sgl_primitive_type_t; - -typedef struct { - uint32_t id; - sg_resource_state state; -} _sgl_slot_t; - -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _sgl_pool_t; - -typedef struct { - _sgl_slot_t slot; - sg_pipeline pip[SGL_NUM_PRIMITIVE_TYPES]; -} _sgl_pipeline_t; - -typedef struct { - _sgl_pool_t pool; - _sgl_pipeline_t* pips; -} _sgl_pipeline_pool_t; - -typedef enum { - SGL_MATRIXMODE_MODELVIEW, - SGL_MATRIXMODE_PROJECTION, - SGL_MATRIXMODE_TEXTURE, - SGL_NUM_MATRIXMODES -} _sgl_matrix_mode_t; - -typedef struct { - float pos[3]; - float uv[2]; - uint32_t rgba; - float psize; -} _sgl_vertex_t; - -typedef struct { - float v[4][4]; -} _sgl_matrix_t; - -typedef struct { - _sgl_matrix_t mvp; /* model-view-projection matrix */ - _sgl_matrix_t tm; /* texture matrix */ -} _sgl_uniform_t; - -typedef enum { - SGL_COMMAND_DRAW, - SGL_COMMAND_VIEWPORT, - SGL_COMMAND_SCISSOR_RECT, -} _sgl_command_type_t; - -typedef struct { - sg_pipeline pip; - sg_image img; - sg_sampler smp; - int base_vertex; - int num_vertices; - int uniform_index; -} _sgl_draw_args_t; - -typedef struct { - int x, y, w, h; - bool origin_top_left; -} _sgl_viewport_args_t; - -typedef struct { - int x, y, w, h; - bool origin_top_left; -} _sgl_scissor_rect_args_t; - -typedef union { - _sgl_draw_args_t draw; - _sgl_viewport_args_t viewport; - _sgl_scissor_rect_args_t scissor_rect; -} _sgl_args_t; - -typedef struct { - _sgl_command_type_t cmd; - int layer_id; - _sgl_args_t args; -} _sgl_command_t; - -#define _SGL_INVALID_SLOT_INDEX (0) -#define _SGL_MAX_STACK_DEPTH (64) -#define _SGL_DEFAULT_CONTEXT_POOL_SIZE (4) -#define _SGL_DEFAULT_PIPELINE_POOL_SIZE (64) -#define _SGL_DEFAULT_MAX_VERTICES (1<<16) -#define _SGL_DEFAULT_MAX_COMMANDS (1<<14) -#define _SGL_SLOT_SHIFT (16) -#define _SGL_MAX_POOL_SIZE (1<<_SGL_SLOT_SHIFT) -#define _SGL_SLOT_MASK (_SGL_MAX_POOL_SIZE-1) - -typedef struct { - _sgl_slot_t slot; - sgl_context_desc_t desc; - uint32_t frame_id; - uint32_t update_frame_id; - struct { - int cap; - int next; - _sgl_vertex_t* ptr; - } vertices; - struct { - int cap; - int next; - _sgl_uniform_t* ptr; - } uniforms; - struct { - int cap; - int next; - _sgl_command_t* ptr; - } commands; - - /* state tracking */ - int base_vertex; - int quad_vtx_count; /* number of times vtx function has been called, used for non-triangle primitives */ - sgl_error_t error; - bool in_begin; - int layer_id; - float u, v; - uint32_t rgba; - float point_size; - _sgl_primitive_type_t cur_prim_type; - sg_image cur_img; - sg_sampler cur_smp; - bool texturing_enabled; - bool matrix_dirty; /* reset in sgl_end(), set in any of the matrix stack functions */ - - /* sokol-gfx resources */ - sg_buffer vbuf; - sgl_pipeline def_pip; - sg_bindings bind; - - /* pipeline stack */ - int pip_tos; - sgl_pipeline pip_stack[_SGL_MAX_STACK_DEPTH]; - - /* matrix stacks */ - _sgl_matrix_mode_t cur_matrix_mode; - int matrix_tos[SGL_NUM_MATRIXMODES]; - _sgl_matrix_t matrix_stack[SGL_NUM_MATRIXMODES][_SGL_MAX_STACK_DEPTH]; -} _sgl_context_t; - -typedef struct { - _sgl_pool_t pool; - _sgl_context_t* contexts; -} _sgl_context_pool_t; - -typedef struct { - uint32_t init_cookie; - sgl_desc_t desc; - sg_image def_img; // a default white texture - sg_sampler def_smp; // a default sampler - sg_shader shd; // same shader for all contexts - sgl_context def_ctx_id; - sgl_context cur_ctx_id; - _sgl_context_t* cur_ctx; // may be 0! - _sgl_pipeline_pool_t pip_pool; - _sgl_context_pool_t context_pool; -} _sgl_t; -static _sgl_t _sgl; - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SGL_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _sgl_log_messages[] = { - _SGL_LOG_ITEMS -}; -#undef _SGL_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SGL_PANIC(code) _sgl_log(SGL_LOGITEM_ ##code, 0, __LINE__) -#define _SGL_ERROR(code) _sgl_log(SGL_LOGITEM_ ##code, 1, __LINE__) -#define _SGL_WARN(code) _sgl_log(SGL_LOGITEM_ ##code, 2, __LINE__) -#define _SGL_INFO(code) _sgl_log(SGL_LOGITEM_ ##code, 3, __LINE__) - -static void _sgl_log(sgl_log_item_t log_item, uint32_t log_level, uint32_t line_nr) { - if (_sgl.desc.logger.func) { - #if defined(SOKOL_DEBUG) - const char* filename = __FILE__; - const char* message = _sgl_log_messages[log_item]; - #else - const char* filename = 0; - const char* message = 0; - #endif - _sgl.desc.logger.func("sgl", log_level, log_item, message, line_nr, filename, _sgl.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -static void _sgl_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -static void* _sgl_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_sgl.desc.allocator.alloc_fn) { - ptr = _sgl.desc.allocator.alloc_fn(size, _sgl.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SGL_PANIC(MALLOC_FAILED); - } - return ptr; -} - -static void* _sgl_malloc_clear(size_t size) { - void* ptr = _sgl_malloc(size); - _sgl_clear(ptr, size); - return ptr; -} - -static void _sgl_free(void* ptr) { - if (_sgl.desc.allocator.free_fn) { - _sgl.desc.allocator.free_fn(ptr, _sgl.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ██████ ██████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ -// -// >>pool -static void _sgl_init_pool(_sgl_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - /* slot 0 is reserved for the 'invalid id', so bump the pool size by 1 */ - pool->size = num + 1; - pool->queue_top = 0; - /* generation counters indexable by pool slot index, slot 0 is reserved */ - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*) _sgl_malloc_clear(gen_ctrs_size); - /* it's not a bug to only reserve 'num' here */ - pool->free_queue = (int*) _sgl_malloc_clear(sizeof(int) * (size_t)num); - /* never allocate the zero-th pool item since the invalid id is 0 */ - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -static void _sgl_discard_pool(_sgl_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _sgl_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _sgl_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -static int _sgl_pool_alloc_index(_sgl_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SGL_INVALID_SLOT_INDEX; - } -} - -static void _sgl_pool_free_index(_sgl_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SGL_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - /* debug check against double-free */ - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -/* allocate the slot at slot_index: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the resource id -*/ -static uint32_t _sgl_slot_alloc(_sgl_pool_t* pool, _sgl_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SGL_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT((slot->state == SG_RESOURCESTATE_INITIAL) && (slot->id == SG_INVALID_ID)); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SGL_SLOT_SHIFT)|(slot_index & _SGL_SLOT_MASK); - slot->state = SG_RESOURCESTATE_ALLOC; - return slot->id; -} - -/* extract slot index from id */ -static int _sgl_slot_index(uint32_t id) { - int slot_index = (int) (id & _SGL_SLOT_MASK); - SOKOL_ASSERT(_SGL_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -// ██████ ██ ██████ ███████ ██ ██ ███ ██ ███████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██████ ██ ██████ █████ ██ ██ ██ ██ ██ █████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ███████ ██ ██ ████ ███████ ███████ -// -// >>pipelines -static void _sgl_reset_pipeline(_sgl_pipeline_t* pip) { - SOKOL_ASSERT(pip); - _sgl_clear(pip, sizeof(_sgl_pipeline_t)); -} - -static void _sgl_setup_pipeline_pool(int pool_size) { - /* note: the pools here will have an additional item, since slot 0 is reserved */ - SOKOL_ASSERT((pool_size > 0) && (pool_size < _SGL_MAX_POOL_SIZE)); - _sgl_init_pool(&_sgl.pip_pool.pool, pool_size); - size_t pool_byte_size = sizeof(_sgl_pipeline_t) * (size_t)_sgl.pip_pool.pool.size; - _sgl.pip_pool.pips = (_sgl_pipeline_t*) _sgl_malloc_clear(pool_byte_size); -} - -static void _sgl_discard_pipeline_pool(void) { - SOKOL_ASSERT(0 != _sgl.pip_pool.pips); - _sgl_free(_sgl.pip_pool.pips); _sgl.pip_pool.pips = 0; - _sgl_discard_pool(&_sgl.pip_pool.pool); -} - -/* get pipeline pointer without id-check */ -static _sgl_pipeline_t* _sgl_pipeline_at(uint32_t pip_id) { - SOKOL_ASSERT(SG_INVALID_ID != pip_id); - int slot_index = _sgl_slot_index(pip_id); - SOKOL_ASSERT((slot_index > _SGL_INVALID_SLOT_INDEX) && (slot_index < _sgl.pip_pool.pool.size)); - return &_sgl.pip_pool.pips[slot_index]; -} - -/* get pipeline pointer with id-check, returns 0 if no match */ -static _sgl_pipeline_t* _sgl_lookup_pipeline(uint32_t pip_id) { - if (SG_INVALID_ID != pip_id) { - _sgl_pipeline_t* pip = _sgl_pipeline_at(pip_id); - if (pip->slot.id == pip_id) { - return pip; - } - } - return 0; -} - -/* make pipeline id from uint32_t id */ -static sgl_pipeline _sgl_make_pip_id(uint32_t pip_id) { - sgl_pipeline pip = { pip_id }; - return pip; -} - -static sgl_pipeline _sgl_alloc_pipeline(void) { - sgl_pipeline res; - int slot_index = _sgl_pool_alloc_index(&_sgl.pip_pool.pool); - if (_SGL_INVALID_SLOT_INDEX != slot_index) { - res = _sgl_make_pip_id(_sgl_slot_alloc(&_sgl.pip_pool.pool, &_sgl.pip_pool.pips[slot_index].slot, slot_index)); - } else { - /* pool is exhausted */ - res = _sgl_make_pip_id(SG_INVALID_ID); - } - return res; -} - -static void _sgl_init_pipeline(sgl_pipeline pip_id, const sg_pipeline_desc* in_desc, const sgl_context_desc_t* ctx_desc) { - SOKOL_ASSERT((pip_id.id != SG_INVALID_ID) && in_desc && ctx_desc); - - /* create a new desc with 'patched' shader and pixel format state */ - sg_pipeline_desc desc = *in_desc; - desc.layout.buffers[0].stride = sizeof(_sgl_vertex_t); - { - sg_vertex_attr_state* pos = &desc.layout.attrs[0]; - pos->offset = offsetof(_sgl_vertex_t, pos); - pos->format = SG_VERTEXFORMAT_FLOAT3; - } - { - sg_vertex_attr_state* uv = &desc.layout.attrs[1]; - uv->offset = offsetof(_sgl_vertex_t, uv); - uv->format = SG_VERTEXFORMAT_FLOAT2; - } - { - sg_vertex_attr_state* rgba = &desc.layout.attrs[2]; - rgba->offset = offsetof(_sgl_vertex_t, rgba); - rgba->format = SG_VERTEXFORMAT_UBYTE4N; - } - { - sg_vertex_attr_state* psize = &desc.layout.attrs[3]; - psize->offset = offsetof(_sgl_vertex_t, psize); - psize->format = SG_VERTEXFORMAT_FLOAT; - } - if (in_desc->shader.id == SG_INVALID_ID) { - desc.shader = _sgl.shd; - } - desc.index_type = SG_INDEXTYPE_NONE; - desc.sample_count = ctx_desc->sample_count; - if (desc.face_winding == _SG_FACEWINDING_DEFAULT) { - desc.face_winding = _sgl.desc.face_winding; - } - desc.depth.pixel_format = ctx_desc->depth_format; - if (ctx_desc->depth_format == SG_PIXELFORMAT_NONE) { - desc.depth.write_enabled = false; - } - desc.colors[0].pixel_format = ctx_desc->color_format; - if (desc.colors[0].write_mask == _SG_COLORMASK_DEFAULT) { - desc.colors[0].write_mask = SG_COLORMASK_RGB; - } - - _sgl_pipeline_t* pip = _sgl_lookup_pipeline(pip_id.id); - SOKOL_ASSERT(pip && (pip->slot.state == SG_RESOURCESTATE_ALLOC)); - pip->slot.state = SG_RESOURCESTATE_VALID; - for (int i = 0; i < SGL_NUM_PRIMITIVE_TYPES; i++) { - switch (i) { - case SGL_PRIMITIVETYPE_POINTS: - desc.primitive_type = SG_PRIMITIVETYPE_POINTS; - break; - case SGL_PRIMITIVETYPE_LINES: - desc.primitive_type = SG_PRIMITIVETYPE_LINES; - break; - case SGL_PRIMITIVETYPE_LINE_STRIP: - desc.primitive_type = SG_PRIMITIVETYPE_LINE_STRIP; - break; - case SGL_PRIMITIVETYPE_TRIANGLES: - desc.primitive_type = SG_PRIMITIVETYPE_TRIANGLES; - break; - case SGL_PRIMITIVETYPE_TRIANGLE_STRIP: - case SGL_PRIMITIVETYPE_QUADS: - desc.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP; - break; - } - if (SGL_PRIMITIVETYPE_QUADS == i) { - /* quads are emulated via triangles, use the same pipeline object */ - pip->pip[i] = pip->pip[SGL_PRIMITIVETYPE_TRIANGLES]; - } else { - pip->pip[i] = sg_make_pipeline(&desc); - if (pip->pip[i].id == SG_INVALID_ID) { - _SGL_ERROR(MAKE_PIPELINE_FAILED); - pip->slot.state = SG_RESOURCESTATE_FAILED; - } - } - } -} - -static sgl_pipeline _sgl_make_pipeline(const sg_pipeline_desc* desc, const sgl_context_desc_t* ctx_desc) { - SOKOL_ASSERT(desc && ctx_desc); - sgl_pipeline pip_id = _sgl_alloc_pipeline(); - if (pip_id.id != SG_INVALID_ID) { - _sgl_init_pipeline(pip_id, desc, ctx_desc); - } else { - _SGL_ERROR(PIPELINE_POOL_EXHAUSTED); - } - return pip_id; -} - -static void _sgl_destroy_pipeline(sgl_pipeline pip_id) { - _sgl_pipeline_t* pip = _sgl_lookup_pipeline(pip_id.id); - if (pip) { - sg_push_debug_group("sokol-gl"); - for (int i = 0; i < SGL_NUM_PRIMITIVE_TYPES; i++) { - if (i != SGL_PRIMITIVETYPE_QUADS) { - sg_destroy_pipeline(pip->pip[i]); - } - } - sg_pop_debug_group(); - _sgl_reset_pipeline(pip); - _sgl_pool_free_index(&_sgl.pip_pool.pool, _sgl_slot_index(pip_id.id)); - } -} - -static sg_pipeline _sgl_get_pipeline(sgl_pipeline pip_id, _sgl_primitive_type_t prim_type) { - _sgl_pipeline_t* pip = _sgl_lookup_pipeline(pip_id.id); - if (pip) { - return pip->pip[prim_type]; - } else { - sg_pipeline dummy_id = { SG_INVALID_ID }; - return dummy_id; - } -} - -// ██████ ██████ ███ ██ ████████ ███████ ██ ██ ████████ ███████ -// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ █████ ███ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██ ████ ██ ███████ ██ ██ ██ ███████ -// -// >>contexts -static void _sgl_reset_context(_sgl_context_t* ctx) { - SOKOL_ASSERT(ctx); - SOKOL_ASSERT(0 == ctx->vertices.ptr); - SOKOL_ASSERT(0 == ctx->uniforms.ptr); - SOKOL_ASSERT(0 == ctx->commands.ptr); - _sgl_clear(ctx, sizeof(_sgl_context_t)); -} - -static void _sgl_setup_context_pool(int pool_size) { - /* note: the pools here will have an additional item, since slot 0 is reserved */ - SOKOL_ASSERT((pool_size > 0) && (pool_size < _SGL_MAX_POOL_SIZE)); - _sgl_init_pool(&_sgl.context_pool.pool, pool_size); - size_t pool_byte_size = sizeof(_sgl_context_t) * (size_t)_sgl.context_pool.pool.size; - _sgl.context_pool.contexts = (_sgl_context_t*) _sgl_malloc_clear(pool_byte_size); -} - -static void _sgl_discard_context_pool(void) { - SOKOL_ASSERT(0 != _sgl.context_pool.contexts); - _sgl_free(_sgl.context_pool.contexts); _sgl.context_pool.contexts = 0; - _sgl_discard_pool(&_sgl.context_pool.pool); -} - -// get context pointer without id-check -static _sgl_context_t* _sgl_context_at(uint32_t ctx_id) { - SOKOL_ASSERT(SG_INVALID_ID != ctx_id); - int slot_index = _sgl_slot_index(ctx_id); - SOKOL_ASSERT((slot_index > _SGL_INVALID_SLOT_INDEX) && (slot_index < _sgl.context_pool.pool.size)); - return &_sgl.context_pool.contexts[slot_index]; -} - -// get context pointer with id-check, returns 0 if no match -static _sgl_context_t* _sgl_lookup_context(uint32_t ctx_id) { - if (SG_INVALID_ID != ctx_id) { - _sgl_context_t* ctx = _sgl_context_at(ctx_id); - if (ctx->slot.id == ctx_id) { - return ctx; - } - } - return 0; -} - -// make context id from uint32_t id -static sgl_context _sgl_make_ctx_id(uint32_t ctx_id) { - sgl_context ctx = { ctx_id }; - return ctx; -} - -static sgl_context _sgl_alloc_context(void) { - sgl_context res; - int slot_index = _sgl_pool_alloc_index(&_sgl.context_pool.pool); - if (_SGL_INVALID_SLOT_INDEX != slot_index) { - res = _sgl_make_ctx_id(_sgl_slot_alloc(&_sgl.context_pool.pool, &_sgl.context_pool.contexts[slot_index].slot, slot_index)); - } else { - // pool is exhausted - res = _sgl_make_ctx_id(SG_INVALID_ID); - } - return res; -} - -// return sgl_context_desc_t with patched defaults -static sgl_context_desc_t _sgl_context_desc_defaults(const sgl_context_desc_t* desc) { - sgl_context_desc_t res = *desc; - res.max_vertices = _sgl_def(desc->max_vertices, _SGL_DEFAULT_MAX_VERTICES); - res.max_commands = _sgl_def(desc->max_commands, _SGL_DEFAULT_MAX_COMMANDS); - return res; -} - -static void _sgl_identity(_sgl_matrix_t*); -static sg_commit_listener _sgl_make_commit_listener(_sgl_context_t* ctx); -static void _sgl_init_context(sgl_context ctx_id, const sgl_context_desc_t* in_desc) { - SOKOL_ASSERT((ctx_id.id != SG_INVALID_ID) && in_desc); - _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - SOKOL_ASSERT(ctx); - ctx->desc = _sgl_context_desc_defaults(in_desc); - // NOTE: frame_id must be non-zero, so that updates trigger in first frame - ctx->frame_id = 1; - ctx->cur_img = _sgl.def_img; - ctx->cur_smp = _sgl.def_smp; - - // allocate buffers and pools - ctx->vertices.cap = ctx->desc.max_vertices; - ctx->commands.cap = ctx->uniforms.cap = ctx->desc.max_commands; - ctx->vertices.ptr = (_sgl_vertex_t*) _sgl_malloc((size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t)); - ctx->uniforms.ptr = (_sgl_uniform_t*) _sgl_malloc((size_t)ctx->uniforms.cap * sizeof(_sgl_uniform_t)); - ctx->commands.ptr = (_sgl_command_t*) _sgl_malloc((size_t)ctx->commands.cap * sizeof(_sgl_command_t)); - - // create sokol-gfx resource objects - sg_push_debug_group("sokol-gl"); - - sg_buffer_desc vbuf_desc; - _sgl_clear(&vbuf_desc, sizeof(vbuf_desc)); - vbuf_desc.size = (size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t); - vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER; - vbuf_desc.usage = SG_USAGE_STREAM; - vbuf_desc.label = "sgl-vertex-buffer"; - ctx->vbuf = sg_make_buffer(&vbuf_desc); - SOKOL_ASSERT(SG_INVALID_ID != ctx->vbuf.id); - ctx->bind.vertex_buffers[0] = ctx->vbuf; - - sg_pipeline_desc def_pip_desc; - _sgl_clear(&def_pip_desc, sizeof(def_pip_desc)); - def_pip_desc.depth.write_enabled = true; - ctx->def_pip = _sgl_make_pipeline(&def_pip_desc, &ctx->desc); - if (!sg_add_commit_listener(_sgl_make_commit_listener(ctx))) { - _SGL_ERROR(ADD_COMMIT_LISTENER_FAILED); - } - sg_pop_debug_group(); - - // default state - ctx->rgba = 0xFFFFFFFF; - ctx->point_size = 1.0f; - for (int i = 0; i < SGL_NUM_MATRIXMODES; i++) { - _sgl_identity(&ctx->matrix_stack[i][0]); - } - ctx->pip_stack[0] = ctx->def_pip; - ctx->matrix_dirty = true; -} - -static sgl_context _sgl_make_context(const sgl_context_desc_t* desc) { - SOKOL_ASSERT(desc); - sgl_context ctx_id = _sgl_alloc_context(); - if (ctx_id.id != SG_INVALID_ID) { - _sgl_init_context(ctx_id, desc); - } else { - _SGL_ERROR(CONTEXT_POOL_EXHAUSTED); - } - return ctx_id; -} - -static void _sgl_destroy_context(sgl_context ctx_id) { - _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - SOKOL_ASSERT(ctx->vertices.ptr); - SOKOL_ASSERT(ctx->uniforms.ptr); - SOKOL_ASSERT(ctx->commands.ptr); - - _sgl_free(ctx->vertices.ptr); - _sgl_free(ctx->uniforms.ptr); - _sgl_free(ctx->commands.ptr); - ctx->vertices.ptr = 0; - ctx->uniforms.ptr = 0; - ctx->commands.ptr = 0; - - sg_push_debug_group("sokol-gl"); - sg_destroy_buffer(ctx->vbuf); - _sgl_destroy_pipeline(ctx->def_pip); - sg_remove_commit_listener(_sgl_make_commit_listener(ctx)); - sg_pop_debug_group(); - - _sgl_reset_context(ctx); - _sgl_pool_free_index(&_sgl.context_pool.pool, _sgl_slot_index(ctx_id.id)); - } -} - -// ███ ███ ██ ███████ ██████ -// ████ ████ ██ ██ ██ -// ██ ████ ██ ██ ███████ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ██████ -// -// >>misc - -static sgl_error_t _sgl_error_defaults(void) { - sgl_error_t defaults = {0}; - return defaults; -} - -static int _sgl_num_vertices(_sgl_context_t* ctx) { - return ctx->vertices.next; -} - -static int _sgl_num_commands(_sgl_context_t* ctx) { - return ctx->commands.next; -} - -static void _sgl_begin(_sgl_context_t* ctx, _sgl_primitive_type_t mode) { - ctx->in_begin = true; - ctx->base_vertex = ctx->vertices.next; - ctx->quad_vtx_count = 0; - ctx->cur_prim_type = mode; -} - -static void _sgl_rewind(_sgl_context_t* ctx) { - ctx->frame_id++; - ctx->vertices.next = 0; - ctx->uniforms.next = 0; - ctx->commands.next = 0; - ctx->base_vertex = 0; - ctx->error = _sgl_error_defaults(); - ctx->layer_id = 0; - ctx->matrix_dirty = true; -} - -// called from inside sokol-gfx sg_commit() -static void _sgl_commit_listener(void* userdata) { - _sgl_context_t* ctx = _sgl_lookup_context((uint32_t)(uintptr_t)userdata); - if (ctx) { - _sgl_rewind(ctx); - } -} - -static sg_commit_listener _sgl_make_commit_listener(_sgl_context_t* ctx) { - sg_commit_listener listener = { _sgl_commit_listener, (void*)(uintptr_t)(ctx->slot.id) }; - return listener; -} - -static _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) { - if (ctx->vertices.next < ctx->vertices.cap) { - return &ctx->vertices.ptr[ctx->vertices.next++]; - } else { - ctx->error.vertices_full = true; - ctx->error.any = true; - return 0; - } -} - -static _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) { - if (ctx->uniforms.next < ctx->uniforms.cap) { - return &ctx->uniforms.ptr[ctx->uniforms.next++]; - } else { - ctx->error.uniforms_full = true; - ctx->error.any = true; - return 0; - } -} - -static _sgl_command_t* _sgl_cur_command(_sgl_context_t* ctx) { - if (ctx->commands.next > 0) { - return &ctx->commands.ptr[ctx->commands.next - 1]; - } else { - return 0; - } -} - -static _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) { - if (ctx->commands.next < ctx->commands.cap) { - return &ctx->commands.ptr[ctx->commands.next++]; - } else { - ctx->error.commands_full = true; - ctx->error.any = true; - return 0; - } -} - -static uint32_t _sgl_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return (uint32_t)(((uint32_t)a<<24)|((uint32_t)b<<16)|((uint32_t)g<<8)|r); -} - -static float _sgl_clamp(float v, float lo, float hi) { - if (v < lo) return lo; - else if (v > hi) return hi; - else return v; -} - -static uint32_t _sgl_pack_rgbaf(float r, float g, float b, float a) { - uint8_t r_u8 = (uint8_t) (_sgl_clamp(r, 0.0f, 1.0f) * 255.0f); - uint8_t g_u8 = (uint8_t) (_sgl_clamp(g, 0.0f, 1.0f) * 255.0f); - uint8_t b_u8 = (uint8_t) (_sgl_clamp(b, 0.0f, 1.0f) * 255.0f); - uint8_t a_u8 = (uint8_t) (_sgl_clamp(a, 0.0f, 1.0f) * 255.0f); - return _sgl_pack_rgbab(r_u8, g_u8, b_u8, a_u8); -} - -static void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, float v, uint32_t rgba) { - SOKOL_ASSERT(ctx->in_begin); - _sgl_vertex_t* vtx; - /* handle non-native primitive types */ - if ((ctx->cur_prim_type == SGL_PRIMITIVETYPE_QUADS) && ((ctx->quad_vtx_count & 3) == 3)) { - /* for quads, before writing the last quad vertex, reuse - the first and third vertex to start the second triangle in the quad - */ - vtx = _sgl_next_vertex(ctx); - if (vtx) { *vtx = *(vtx - 3); } - vtx = _sgl_next_vertex(ctx); - if (vtx) { *vtx = *(vtx - 2); } - } - vtx = _sgl_next_vertex(ctx); - if (vtx) { - vtx->pos[0] = x; vtx->pos[1] = y; vtx->pos[2] = z; - vtx->uv[0] = u; vtx->uv[1] = v; - vtx->rgba = rgba; - vtx->psize = ctx->point_size; - } - ctx->quad_vtx_count++; -} - -static void _sgl_identity(_sgl_matrix_t* m) { - for (int c = 0; c < 4; c++) { - for (int r = 0; r < 4; r++) { - m->v[c][r] = (r == c) ? 1.0f : 0.0f; - } - } -} - -static void _sgl_transpose(_sgl_matrix_t* dst, const _sgl_matrix_t* m) { - SOKOL_ASSERT(dst != m); - for (int c = 0; c < 4; c++) { - for (int r = 0; r < 4; r++) { - dst->v[r][c] = m->v[c][r]; - } - } -} - -/* _sgl_rotate, _sgl_frustum, _sgl_ortho from MESA m_matric.c */ -static void _sgl_matmul4(_sgl_matrix_t* p, const _sgl_matrix_t* a, const _sgl_matrix_t* b) { - for (int r = 0; r < 4; r++) { - float ai0=a->v[0][r], ai1=a->v[1][r], ai2=a->v[2][r], ai3=a->v[3][r]; - p->v[0][r] = ai0*b->v[0][0] + ai1*b->v[0][1] + ai2*b->v[0][2] + ai3*b->v[0][3]; - p->v[1][r] = ai0*b->v[1][0] + ai1*b->v[1][1] + ai2*b->v[1][2] + ai3*b->v[1][3]; - p->v[2][r] = ai0*b->v[2][0] + ai1*b->v[2][1] + ai2*b->v[2][2] + ai3*b->v[2][3]; - p->v[3][r] = ai0*b->v[3][0] + ai1*b->v[3][1] + ai2*b->v[3][2] + ai3*b->v[3][3]; - } -} - -static void _sgl_mul(_sgl_matrix_t* dst, const _sgl_matrix_t* m) { - _sgl_matmul4(dst, dst, m); -} - -static void _sgl_rotate(_sgl_matrix_t* dst, float a, float x, float y, float z) { - - float s = sinf(a); - float c = cosf(a); - - float mag = sqrtf(x*x + y*y + z*z); - if (mag < 1.0e-4F) { - return; - } - x /= mag; - y /= mag; - z /= mag; - float xx = x * x; - float yy = y * y; - float zz = z * z; - float xy = x * y; - float yz = y * z; - float zx = z * x; - float xs = x * s; - float ys = y * s; - float zs = z * s; - float one_c = 1.0f - c; - - _sgl_matrix_t m; - m.v[0][0] = (one_c * xx) + c; - m.v[1][0] = (one_c * xy) - zs; - m.v[2][0] = (one_c * zx) + ys; - m.v[3][0] = 0.0f; - m.v[0][1] = (one_c * xy) + zs; - m.v[1][1] = (one_c * yy) + c; - m.v[2][1] = (one_c * yz) - xs; - m.v[3][1] = 0.0f; - m.v[0][2] = (one_c * zx) - ys; - m.v[1][2] = (one_c * yz) + xs; - m.v[2][2] = (one_c * zz) + c; - m.v[3][2] = 0.0f; - m.v[0][3] = 0.0f; - m.v[1][3] = 0.0f; - m.v[2][3] = 0.0f; - m.v[3][3] = 1.0f; - _sgl_mul(dst, &m); -} - -static void _sgl_scale(_sgl_matrix_t* dst, float x, float y, float z) { - for (int r = 0; r < 4; r++) { - dst->v[0][r] *= x; - dst->v[1][r] *= y; - dst->v[2][r] *= z; - } -} - -static void _sgl_translate(_sgl_matrix_t* dst, float x, float y, float z) { - for (int r = 0; r < 4; r++) { - dst->v[3][r] = dst->v[0][r]*x + dst->v[1][r]*y + dst->v[2][r]*z + dst->v[3][r]; - } -} - -static void _sgl_frustum(_sgl_matrix_t* dst, float left, float right, float bottom, float top, float znear, float zfar) { - float x = (2.0f * znear) / (right - left); - float y = (2.0f * znear) / (top - bottom); - float a = (right + left) / (right - left); - float b = (top + bottom) / (top - bottom); - float c = -(zfar + znear) / (zfar - znear); - float d = -(2.0f * zfar * znear) / (zfar - znear); - _sgl_matrix_t m; - m.v[0][0] = x; m.v[0][1] = 0.0f; m.v[0][2] = 0.0f; m.v[0][3] = 0.0f; - m.v[1][0] = 0.0f; m.v[1][1] = y; m.v[1][2] = 0.0f; m.v[1][3] = 0.0f; - m.v[2][0] = a; m.v[2][1] = b; m.v[2][2] = c; m.v[2][3] = -1.0f; - m.v[3][0] = 0.0f; m.v[3][1] = 0.0f; m.v[3][2] = d; m.v[3][3] = 0.0f; - _sgl_mul(dst, &m); -} - -static void _sgl_ortho(_sgl_matrix_t* dst, float left, float right, float bottom, float top, float znear, float zfar) { - _sgl_matrix_t m; - m.v[0][0] = 2.0f / (right - left); - m.v[1][0] = 0.0f; - m.v[2][0] = 0.0f; - m.v[3][0] = -(right + left) / (right - left); - m.v[0][1] = 0.0f; - m.v[1][1] = 2.0f / (top - bottom); - m.v[2][1] = 0.0f; - m.v[3][1] = -(top + bottom) / (top - bottom); - m.v[0][2] = 0.0f; - m.v[1][2] = 0.0f; - m.v[2][2] = -2.0f / (zfar - znear); - m.v[3][2] = -(zfar + znear) / (zfar - znear); - m.v[0][3] = 0.0f; - m.v[1][3] = 0.0f; - m.v[2][3] = 0.0f; - m.v[3][3] = 1.0f; - - _sgl_mul(dst, &m); -} - -/* _sgl_perspective, _sgl_lookat from Regal project.c */ -static void _sgl_perspective(_sgl_matrix_t* dst, float fovy, float aspect, float znear, float zfar) { - float sine = sinf(fovy / 2.0f); - float delta_z = zfar - znear; - if ((delta_z == 0.0f) || (sine == 0.0f) || (aspect == 0.0f)) { - return; - } - float cotan = cosf(fovy / 2.0f) / sine; - _sgl_matrix_t m; - _sgl_identity(&m); - m.v[0][0] = cotan / aspect; - m.v[1][1] = cotan; - m.v[2][2] = -(zfar + znear) / delta_z; - m.v[2][3] = -1.0f; - m.v[3][2] = -2.0f * znear * zfar / delta_z; - m.v[3][3] = 0.0f; - _sgl_mul(dst, &m); -} - -static void _sgl_normalize(float v[3]) { - float r = sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); - if (r == 0.0f) { - return; - } - v[0] /= r; - v[1] /= r; - v[2] /= r; -} - -static void _sgl_cross(float v1[3], float v2[3], float res[3]) { - res[0] = v1[1]*v2[2] - v1[2]*v2[1]; - res[1] = v1[2]*v2[0] - v1[0]*v2[2]; - res[2] = v1[0]*v2[1] - v1[1]*v2[0]; -} - -static void _sgl_lookat(_sgl_matrix_t* dst, - 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) -{ - float fwd[3], side[3], up[3]; - - fwd[0] = center_x - eye_x; fwd[1] = center_y - eye_y; fwd[2] = center_z - eye_z; - up[0] = up_x; up[1] = up_y; up[2] = up_z; - _sgl_normalize(fwd); - _sgl_cross(fwd, up, side); - _sgl_normalize(side); - _sgl_cross(side, fwd, up); - - _sgl_matrix_t m; - _sgl_identity(&m); - m.v[0][0] = side[0]; - m.v[1][0] = side[1]; - m.v[2][0] = side[2]; - m.v[0][1] = up[0]; - m.v[1][1] = up[1]; - m.v[2][1] = up[2]; - m.v[0][2] = -fwd[0]; - m.v[1][2] = -fwd[1]; - m.v[2][2] = -fwd[2]; - _sgl_mul(dst, &m); - _sgl_translate(dst, -eye_x, -eye_y, -eye_z); -} - -/* current top-of-stack projection matrix */ -static _sgl_matrix_t* _sgl_matrix_projection(_sgl_context_t* ctx) { - return &ctx->matrix_stack[SGL_MATRIXMODE_PROJECTION][ctx->matrix_tos[SGL_MATRIXMODE_PROJECTION]]; -} - -/* get top-of-stack modelview matrix */ -static _sgl_matrix_t* _sgl_matrix_modelview(_sgl_context_t* ctx) { - return &ctx->matrix_stack[SGL_MATRIXMODE_MODELVIEW][ctx->matrix_tos[SGL_MATRIXMODE_MODELVIEW]]; -} - -/* get top-of-stack texture matrix */ -static _sgl_matrix_t* _sgl_matrix_texture(_sgl_context_t* ctx) { - return &ctx->matrix_stack[SGL_MATRIXMODE_TEXTURE][ctx->matrix_tos[SGL_MATRIXMODE_TEXTURE]]; -} - -/* get pointer to current top-of-stack of current matrix mode */ -static _sgl_matrix_t* _sgl_matrix(_sgl_context_t* ctx) { - return &ctx->matrix_stack[ctx->cur_matrix_mode][ctx->matrix_tos[ctx->cur_matrix_mode]]; -} - -// return sg_context_desc_t with patched defaults -static sgl_desc_t _sgl_desc_defaults(const sgl_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sgl_desc_t res = *desc; - res.max_vertices = _sgl_def(desc->max_vertices, _SGL_DEFAULT_MAX_VERTICES); - res.max_commands = _sgl_def(desc->max_commands, _SGL_DEFAULT_MAX_COMMANDS); - res.context_pool_size = _sgl_def(desc->context_pool_size, _SGL_DEFAULT_CONTEXT_POOL_SIZE); - res.pipeline_pool_size = _sgl_def(desc->pipeline_pool_size, _SGL_DEFAULT_PIPELINE_POOL_SIZE); - res.face_winding = _sgl_def(desc->face_winding, SG_FACEWINDING_CCW); - return res; -} - -// create resources which are shared between all contexts -static void _sgl_setup_common(void) { - sg_push_debug_group("sokol-gl"); - - uint32_t pixels[64]; - for (int i = 0; i < 64; i++) { - pixels[i] = 0xFFFFFFFF; - } - sg_image_desc img_desc; - _sgl_clear(&img_desc, sizeof(img_desc)); - img_desc.type = SG_IMAGETYPE_2D; - img_desc.width = 8; - img_desc.height = 8; - img_desc.num_mipmaps = 1; - img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; - img_desc.data.subimage[0][0] = SG_RANGE(pixels); - img_desc.label = "sgl-default-texture"; - _sgl.def_img = sg_make_image(&img_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sgl.def_img.id); - - sg_sampler_desc smp_desc; - _sgl_clear(&smp_desc, sizeof(smp_desc)); - smp_desc.min_filter = SG_FILTER_NEAREST; - smp_desc.mag_filter = SG_FILTER_NEAREST; - _sgl.def_smp = sg_make_sampler(&smp_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sgl.def_smp.id); - - // one shader for all contexts - sg_shader_desc shd_desc; - _sgl_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[3].name = "psize"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - shd_desc.attrs[3].sem_name = "TEXCOORD"; - shd_desc.attrs[3].sem_index = 3; - sg_shader_uniform_block_desc* ub = &shd_desc.vs.uniform_blocks[0]; - ub->size = sizeof(_sgl_uniform_t); - ub->uniforms[0].name = "vs_params"; - ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - ub->uniforms[0].array_count = 8; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - shd_desc.label = "sgl-shader"; - #if defined(SOKOL_GLCORE) - shd_desc.vs.source = (const char*)_sgl_vs_source_glsl410; - shd_desc.fs.source = (const char*)_sgl_fs_source_glsl410; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = (const char*)_sgl_vs_source_glsl300es; - shd_desc.fs.source = (const char*)_sgl_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = (const char*)_sgl_vs_source_metal_sim; - shd_desc.fs.source = (const char*)_sgl_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = (const char*)_sgl_vs_source_wgsl; - shd_desc.fs.source = (const char*)_sgl_fs_source_wgsl; - #else - shd_desc.vs.source = _sgl_vs_source_dummy; - shd_desc.fs.source = _sgl_fs_source_dummy; - #endif - _sgl.shd = sg_make_shader(&shd_desc); - SOKOL_ASSERT(SG_INVALID_ID != _sgl.shd.id); - sg_pop_debug_group(); -} - -// discard resources which are shared between all contexts -static void _sgl_discard_common(void) { - sg_push_debug_group("sokol-gl"); - sg_destroy_image(_sgl.def_img); - sg_destroy_sampler(_sgl.def_smp); - sg_destroy_shader(_sgl.shd); - sg_pop_debug_group(); -} - -static bool _sgl_is_default_context(sgl_context ctx_id) { - return ctx_id.id == SGL_DEFAULT_CONTEXT.id; -} - -static void _sgl_draw(_sgl_context_t* ctx, int layer_id) { - SOKOL_ASSERT(ctx); - if ((ctx->vertices.next > 0) && (ctx->commands.next > 0)) { - sg_push_debug_group("sokol-gl"); - - uint32_t cur_pip_id = SG_INVALID_ID; - uint32_t cur_img_id = SG_INVALID_ID; - uint32_t cur_smp_id = SG_INVALID_ID; - int cur_uniform_index = -1; - - if (ctx->update_frame_id != ctx->frame_id) { - ctx->update_frame_id = ctx->frame_id; - const sg_range range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sgl_vertex_t) }; - sg_update_buffer(ctx->vbuf, &range); - } - - // render all successfully recorded commands (this may be less than the - // issued commands if we're in an error state) - for (int i = 0; i < ctx->commands.next; i++) { - const _sgl_command_t* cmd = &ctx->commands.ptr[i]; - if (cmd->layer_id != layer_id) { - continue; - } - switch (cmd->cmd) { - case SGL_COMMAND_VIEWPORT: - { - const _sgl_viewport_args_t* args = &cmd->args.viewport; - sg_apply_viewport(args->x, args->y, args->w, args->h, args->origin_top_left); - } - break; - case SGL_COMMAND_SCISSOR_RECT: - { - const _sgl_scissor_rect_args_t* args = &cmd->args.scissor_rect; - sg_apply_scissor_rect(args->x, args->y, args->w, args->h, args->origin_top_left); - } - break; - case SGL_COMMAND_DRAW: - { - const _sgl_draw_args_t* args = &cmd->args.draw; - if (args->pip.id != cur_pip_id) { - sg_apply_pipeline(args->pip); - cur_pip_id = args->pip.id; - /* when pipeline changes, also need to re-apply uniforms and bindings */ - cur_img_id = SG_INVALID_ID; - cur_smp_id = SG_INVALID_ID; - cur_uniform_index = -1; - } - if ((cur_img_id != args->img.id) || (cur_smp_id != args->smp.id)) { - ctx->bind.fs.images[0] = args->img; - ctx->bind.fs.samplers[0] = args->smp; - sg_apply_bindings(&ctx->bind); - cur_img_id = args->img.id; - cur_smp_id = args->smp.id; - } - if (cur_uniform_index != args->uniform_index) { - const sg_range ub_range = { &ctx->uniforms.ptr[args->uniform_index], sizeof(_sgl_uniform_t) }; - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &ub_range); - cur_uniform_index = args->uniform_index; - } - /* FIXME: what if number of vertices doesn't match the primitive type? */ - if (args->num_vertices > 0) { - sg_draw(args->base_vertex, args->num_vertices, 1); - } - } - break; - } - } - sg_pop_debug_group(); - } -} - -static sgl_context_desc_t _sgl_as_context_desc(const sgl_desc_t* desc) { - sgl_context_desc_t ctx_desc; - _sgl_clear(&ctx_desc, sizeof(ctx_desc)); - ctx_desc.max_vertices = desc->max_vertices; - ctx_desc.max_commands = desc->max_commands; - ctx_desc.color_format = desc->color_format; - ctx_desc.depth_format = desc->depth_format; - ctx_desc.sample_count = desc->sample_count; - return ctx_desc; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) { - SOKOL_ASSERT(desc); - _sgl_clear(&_sgl, sizeof(_sgl)); - _sgl.init_cookie = _SGL_INIT_COOKIE; - _sgl.desc = _sgl_desc_defaults(desc); - _sgl_setup_pipeline_pool(_sgl.desc.pipeline_pool_size); - _sgl_setup_context_pool(_sgl.desc.context_pool_size); - _sgl_setup_common(); - const sgl_context_desc_t ctx_desc = _sgl_as_context_desc(&_sgl.desc); - _sgl.def_ctx_id = sgl_make_context(&ctx_desc); - SOKOL_ASSERT(SGL_DEFAULT_CONTEXT.id == _sgl.def_ctx_id.id); - sgl_set_context(_sgl.def_ctx_id); -} - -SOKOL_API_IMPL void sgl_shutdown(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - // contexts own a pipeline, so destroy contexts before pipelines - for (int i = 0; i < _sgl.context_pool.pool.size; i++) { - _sgl_context_t* ctx = &_sgl.context_pool.contexts[i]; - _sgl_destroy_context(_sgl_make_ctx_id(ctx->slot.id)); - } - for (int i = 0; i < _sgl.pip_pool.pool.size; i++) { - _sgl_pipeline_t* pip = &_sgl.pip_pool.pips[i]; - _sgl_destroy_pipeline(_sgl_make_pip_id(pip->slot.id)); - } - _sgl_discard_context_pool(); - _sgl_discard_pipeline_pool(); - _sgl_discard_common(); - _sgl.init_cookie = 0; -} - -SOKOL_API_IMPL sgl_error_t sgl_error(void) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - return ctx->error; - } else { - sgl_error_t err = _sgl_error_defaults(); - err.no_context = true; - err.any = true; - return err; - } -} - -SOKOL_API_IMPL sgl_error_t sgl_context_error(sgl_context ctx_id) { - const _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - return ctx->error; - } else { - sgl_error_t err = _sgl_error_defaults(); - err.no_context = true; - err.any = true; - return err; - } -} - -SOKOL_API_IMPL float sgl_rad(float deg) { - return (deg * (float)M_PI) / 180.0f; -} - -SOKOL_API_IMPL float sgl_deg(float rad) { - return (rad * 180.0f) / (float)M_PI; -} - -SOKOL_API_IMPL sgl_context sgl_make_context(const sgl_context_desc_t* desc) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - return _sgl_make_context(desc); -} - -SOKOL_API_IMPL void sgl_destroy_context(sgl_context ctx_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - if (_sgl_is_default_context(ctx_id)) { - _SGL_WARN(CANNOT_DESTROY_DEFAULT_CONTEXT); - return; - } - _sgl_destroy_context(ctx_id); - // re-validate the current context pointer (this will return a nullptr - // if we just destroyed the current context) - _sgl.cur_ctx = _sgl_lookup_context(_sgl.cur_ctx_id.id); -} - -SOKOL_API_IMPL void sgl_set_context(sgl_context ctx_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - if (_sgl_is_default_context(ctx_id)) { - _sgl.cur_ctx_id = _sgl.def_ctx_id; - } else { - _sgl.cur_ctx_id = ctx_id; - } - // this will return null if the handle isn't valid - _sgl.cur_ctx = _sgl_lookup_context(_sgl.cur_ctx_id.id); -} - -SOKOL_API_IMPL sgl_context sgl_get_context(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - return _sgl.cur_ctx_id; -} - -SOKOL_API_IMPL sgl_context sgl_default_context(void) { - return SGL_DEFAULT_CONTEXT; -} - -SOKOL_API_IMPL int sgl_num_vertices(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - return _sgl_num_vertices(ctx); - } else { - return 0; - } -} - -SOKOL_API_IMPL int sgl_num_commands(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - return _sgl_num_commands(ctx); - } else { - return 0; - } -} - -SOKOL_API_IMPL sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - return _sgl_make_pipeline(desc, &ctx->desc); - } else { - return _sgl_make_pip_id(SG_INVALID_ID); - } -} - -SOKOL_API_IMPL sgl_pipeline sgl_context_make_pipeline(sgl_context ctx_id, const sg_pipeline_desc* desc) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - const _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - return _sgl_make_pipeline(desc, &ctx->desc); - } else { - return _sgl_make_pip_id(SG_INVALID_ID); - } -} - -SOKOL_API_IMPL void sgl_destroy_pipeline(sgl_pipeline pip_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_destroy_pipeline(pip_id); -} - -SOKOL_API_IMPL void sgl_load_pipeline(sgl_pipeline pip_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT((ctx->pip_tos >= 0) && (ctx->pip_tos < _SGL_MAX_STACK_DEPTH)); - ctx->pip_stack[ctx->pip_tos] = pip_id; -} - -SOKOL_API_IMPL void sgl_load_default_pipeline(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT((ctx->pip_tos >= 0) && (ctx->pip_tos < _SGL_MAX_STACK_DEPTH)); - ctx->pip_stack[ctx->pip_tos] = ctx->def_pip; -} - -SOKOL_API_IMPL void sgl_push_pipeline(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - if (ctx->pip_tos < (_SGL_MAX_STACK_DEPTH - 1)) { - ctx->pip_tos++; - ctx->pip_stack[ctx->pip_tos] = ctx->pip_stack[ctx->pip_tos-1]; - } else { - ctx->error.stack_overflow = true; - ctx->error.any = true; - } -} - -SOKOL_API_IMPL void sgl_pop_pipeline(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - if (ctx->pip_tos > 0) { - ctx->pip_tos--; - } else { - ctx->error.stack_underflow = true; - ctx->error.any = true; - } -} - -SOKOL_API_IMPL void sgl_defaults(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - ctx->u = 0.0f; ctx->v = 0.0f; - ctx->rgba = 0xFFFFFFFF; - ctx->point_size = 1.0f; - ctx->texturing_enabled = false; - ctx->cur_img = _sgl.def_img; - ctx->cur_smp = _sgl.def_smp; - sgl_load_default_pipeline(); - _sgl_identity(_sgl_matrix_texture(ctx)); - _sgl_identity(_sgl_matrix_modelview(ctx)); - _sgl_identity(_sgl_matrix_projection(ctx)); - ctx->cur_matrix_mode = SGL_MATRIXMODE_MODELVIEW; - ctx->matrix_dirty = true; -} - -SOKOL_API_IMPL void sgl_layer(int layer_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - ctx->layer_id = layer_id; -} - -SOKOL_API_IMPL void sgl_viewport(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_command_t* cmd = _sgl_next_command(ctx); - if (cmd) { - cmd->cmd = SGL_COMMAND_VIEWPORT; - cmd->layer_id = ctx->layer_id; - cmd->args.viewport.x = x; - cmd->args.viewport.y = y; - cmd->args.viewport.w = w; - cmd->args.viewport.h = h; - cmd->args.viewport.origin_top_left = origin_top_left; - } -} - -SOKOL_API_IMPL void sgl_viewportf(float x, float y, float w, float h, bool origin_top_left) { - sgl_viewport((int)x, (int)y, (int)w, (int)h, origin_top_left); -} - -SOKOL_API_IMPL void sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_command_t* cmd = _sgl_next_command(ctx); - if (cmd) { - cmd->cmd = SGL_COMMAND_SCISSOR_RECT; - cmd->layer_id = ctx->layer_id; - cmd->args.scissor_rect.x = x; - cmd->args.scissor_rect.y = y; - cmd->args.scissor_rect.w = w; - cmd->args.scissor_rect.h = h; - cmd->args.scissor_rect.origin_top_left = origin_top_left; - } -} - -SOKOL_API_IMPL void sgl_scissor_rectf(float x, float y, float w, float h, bool origin_top_left) { - sgl_scissor_rect((int)x, (int)y, (int)w, (int)h, origin_top_left); -} - -SOKOL_API_IMPL void sgl_enable_texture(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - ctx->texturing_enabled = true; -} - -SOKOL_API_IMPL void sgl_disable_texture(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - ctx->texturing_enabled = false; -} - -SOKOL_API_IMPL void sgl_texture(sg_image img, sg_sampler smp) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - if (SG_INVALID_ID != img.id) { - ctx->cur_img = img; - } else { - ctx->cur_img = _sgl.def_img; - } - if (SG_INVALID_ID != smp.id) { - ctx->cur_smp = smp; - } else { - ctx->cur_smp = _sgl.def_smp; - } -} - -SOKOL_API_IMPL void sgl_begin_points(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_POINTS); -} - -SOKOL_API_IMPL void sgl_begin_lines(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_LINES); -} - -SOKOL_API_IMPL void sgl_begin_line_strip(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_LINE_STRIP); -} - -SOKOL_API_IMPL void sgl_begin_triangles(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_TRIANGLES); -} - -SOKOL_API_IMPL void sgl_begin_triangle_strip(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_TRIANGLE_STRIP); -} - -SOKOL_API_IMPL void sgl_begin_quads(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(!ctx->in_begin); - _sgl_begin(ctx, SGL_PRIMITIVETYPE_QUADS); -} - -SOKOL_API_IMPL void sgl_end(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT(ctx->in_begin); - SOKOL_ASSERT(ctx->vertices.next >= ctx->base_vertex); - ctx->in_begin = false; - - bool matrix_dirty = ctx->matrix_dirty; - if (matrix_dirty) { - ctx->matrix_dirty = false; - _sgl_uniform_t* uni = _sgl_next_uniform(ctx); - if (uni) { - _sgl_matmul4(&uni->mvp, _sgl_matrix_projection(ctx), _sgl_matrix_modelview(ctx)); - uni->tm = *_sgl_matrix_texture(ctx); - } - } - - // don't record any new commands when we're in an error state - if (ctx->error.any) { - return; - } - - // check if command can be merged with current command - sg_pipeline pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type); - sg_image img = ctx->texturing_enabled ? ctx->cur_img : _sgl.def_img; - sg_sampler smp = ctx->texturing_enabled ? ctx->cur_smp : _sgl.def_smp; - _sgl_command_t* cur_cmd = _sgl_cur_command(ctx); - bool merge_cmd = false; - if (cur_cmd) { - if ((cur_cmd->cmd == SGL_COMMAND_DRAW) && - (cur_cmd->layer_id == ctx->layer_id) && - (ctx->cur_prim_type != SGL_PRIMITIVETYPE_LINE_STRIP) && - (ctx->cur_prim_type != SGL_PRIMITIVETYPE_TRIANGLE_STRIP) && - !matrix_dirty && - (cur_cmd->args.draw.img.id == img.id) && - (cur_cmd->args.draw.smp.id == smp.id) && - (cur_cmd->args.draw.pip.id == pip.id)) - { - merge_cmd = true; - } - } - if (merge_cmd) { - // draw command can be merged with the previous command - cur_cmd->args.draw.num_vertices += ctx->vertices.next - ctx->base_vertex; - } else { - // append a new draw command - _sgl_command_t* cmd = _sgl_next_command(ctx); - if (cmd) { - SOKOL_ASSERT(ctx->uniforms.next > 0); - cmd->cmd = SGL_COMMAND_DRAW; - cmd->layer_id = ctx->layer_id; - cmd->args.draw.img = img; - cmd->args.draw.smp = smp; - cmd->args.draw.pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type); - cmd->args.draw.base_vertex = ctx->base_vertex; - cmd->args.draw.num_vertices = ctx->vertices.next - ctx->base_vertex; - cmd->args.draw.uniform_index = ctx->uniforms.next - 1; - } - } -} - -SOKOL_API_IMPL void sgl_point_size(float s) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->point_size = s; - } -} - -SOKOL_API_IMPL void sgl_t2f(float u, float v) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->u = u; - ctx->v = v; - } -} - -SOKOL_API_IMPL void sgl_c3f(float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = _sgl_pack_rgbaf(r, g, b, 1.0f); - } -} - -SOKOL_API_IMPL void sgl_c4f(float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = _sgl_pack_rgbaf(r, g, b, a); - } -} - -SOKOL_API_IMPL void sgl_c3b(uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = _sgl_pack_rgbab(r, g, b, 255); - } -} - -SOKOL_API_IMPL void sgl_c4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = _sgl_pack_rgbab(r, g, b, a); - } -} - -SOKOL_API_IMPL void sgl_c1i(uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->rgba = rgba; - } -} - -SOKOL_API_IMPL void sgl_v2f(float x, float y) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, ctx->rgba); - } -} - -SOKOL_API_IMPL void sgl_v3f(float x, float y, float z) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, ctx->rgba); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f(float x, float y, float u, float v) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, ctx->rgba); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f(float x, float y, float z, float u, float v) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, ctx->rgba); - } -} - -SOKOL_API_IMPL void sgl_v2f_c3f(float x, float y, float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, _sgl_pack_rgbaf(r, g, b, 1.0f)); - } -} - -SOKOL_API_IMPL void sgl_v2f_c3b(float x, float y, uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, _sgl_pack_rgbab(r, g, b, 255)); - } -} - -SOKOL_API_IMPL void sgl_v2f_c4f(float x, float y, float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, _sgl_pack_rgbaf(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v2f_c4b(float x, float y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, _sgl_pack_rgbab(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v2f_c1i(float x, float y, uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, ctx->u, ctx->v, rgba); - } -} - -SOKOL_API_IMPL void sgl_v3f_c3f(float x, float y, float z, float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, _sgl_pack_rgbaf(r, g, b, 1.0f)); - } -} - -SOKOL_API_IMPL void sgl_v3f_c3b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, _sgl_pack_rgbab(r, g, b, 255)); - } -} - -SOKOL_API_IMPL void sgl_v3f_c4f(float x, float y, float z, float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, _sgl_pack_rgbaf(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v3f_c4b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, _sgl_pack_rgbab(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v3f_c1i(float x, float y, float z, uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, ctx->u, ctx->v, rgba); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c3f(float x, float y, float u, float v, float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, _sgl_pack_rgbaf(r, g, b, 1.0f)); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c3b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, _sgl_pack_rgbab(r, g, b, 255)); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c4f(float x, float y, float u, float v, float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, _sgl_pack_rgbaf(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c4b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, _sgl_pack_rgbab(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v2f_t2f_c1i(float x, float y, float u, float v, uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, 0.0f, u, v, rgba); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c3f(float x, float y, float z, float u, float v, float r, float g, float b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, _sgl_pack_rgbaf(r, g, b, 1.0f)); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c3b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, _sgl_pack_rgbab(r, g, b, 255)); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c4f(float x, float y, float z, float u, float v, float r, float g, float b, float a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, _sgl_pack_rgbaf(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c4b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx, x, y, z, u, v, _sgl_pack_rgbab(r, g, b, a)); - } -} - -SOKOL_API_IMPL void sgl_v3f_t2f_c1i(float x, float y, float z, float u, float v, uint32_t rgba) { - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_vtx(ctx,x, y, z, u, v, rgba); - } -} - -SOKOL_API_IMPL void sgl_matrix_mode_modelview(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->cur_matrix_mode = SGL_MATRIXMODE_MODELVIEW; - } -} - -SOKOL_API_IMPL void sgl_matrix_mode_projection(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->cur_matrix_mode = SGL_MATRIXMODE_PROJECTION; - } -} - -SOKOL_API_IMPL void sgl_matrix_mode_texture(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - ctx->cur_matrix_mode = SGL_MATRIXMODE_TEXTURE; - } -} - -SOKOL_API_IMPL void sgl_load_identity(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_identity(_sgl_matrix(ctx)); -} - -SOKOL_API_IMPL void sgl_load_matrix(const float m[16]) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - memcpy(&_sgl_matrix(ctx)->v[0][0], &m[0], 64); -} - -SOKOL_API_IMPL void sgl_load_transpose_matrix(const float m[16]) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_transpose(_sgl_matrix(ctx), (const _sgl_matrix_t*) &m[0]); -} - -SOKOL_API_IMPL void sgl_mult_matrix(const float m[16]) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - const _sgl_matrix_t* m0 = (const _sgl_matrix_t*) &m[0]; - _sgl_mul(_sgl_matrix(ctx), m0); -} - -SOKOL_API_IMPL void sgl_mult_transpose_matrix(const float m[16]) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_matrix_t m0; - _sgl_transpose(&m0, (const _sgl_matrix_t*) &m[0]); - _sgl_mul(_sgl_matrix(ctx), &m0); -} - -SOKOL_API_IMPL void sgl_rotate(float angle_rad, float x, float y, float z) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_rotate(_sgl_matrix(ctx), angle_rad, x, y, z); -} - -SOKOL_API_IMPL void sgl_scale(float x, float y, float z) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_scale(_sgl_matrix(ctx), x, y, z); -} - -SOKOL_API_IMPL void sgl_translate(float x, float y, float z) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_translate(_sgl_matrix(ctx), x, y, z); -} - -SOKOL_API_IMPL void sgl_frustum(float l, float r, float b, float t, float n, float f) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_frustum(_sgl_matrix(ctx), l, r, b, t, n, f); -} - -SOKOL_API_IMPL void sgl_ortho(float l, float r, float b, float t, float n, float f) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_ortho(_sgl_matrix(ctx), l, r, b, t, n, f); -} - -SOKOL_API_IMPL void sgl_perspective(float fov_y, float aspect, float z_near, float z_far) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_perspective(_sgl_matrix(ctx), fov_y, aspect, z_near, z_far); -} - -SOKOL_API_IMPL void 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) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - ctx->matrix_dirty = true; - _sgl_lookat(_sgl_matrix(ctx), eye_x, eye_y, eye_z, center_x, center_y, center_z, up_x, up_y, up_z); -} - -SOKOL_GL_API_DECL void sgl_push_matrix(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT((ctx->cur_matrix_mode >= 0) && (ctx->cur_matrix_mode < SGL_NUM_MATRIXMODES)); - ctx->matrix_dirty = true; - if (ctx->matrix_tos[ctx->cur_matrix_mode] < (_SGL_MAX_STACK_DEPTH - 1)) { - const _sgl_matrix_t* src = _sgl_matrix(ctx); - ctx->matrix_tos[ctx->cur_matrix_mode]++; - _sgl_matrix_t* dst = _sgl_matrix(ctx); - *dst = *src; - } else { - ctx->error.stack_overflow = true; - ctx->error.any = true; - } -} - -SOKOL_GL_API_DECL void sgl_pop_matrix(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (!ctx) { - return; - } - SOKOL_ASSERT((ctx->cur_matrix_mode >= 0) && (ctx->cur_matrix_mode < SGL_NUM_MATRIXMODES)); - ctx->matrix_dirty = true; - if (ctx->matrix_tos[ctx->cur_matrix_mode] > 0) { - ctx->matrix_tos[ctx->cur_matrix_mode]--; - } else { - ctx->error.stack_underflow = true; - ctx->error.any = true; - } -} - -SOKOL_API_IMPL void sgl_draw(void) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_draw(ctx, 0); - } -} - -SOKOL_API_IMPL void sgl_draw_layer(int layer_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl.cur_ctx; - if (ctx) { - _sgl_draw(ctx, layer_id); - } -} - -SOKOL_API_IMPL void sgl_context_draw(sgl_context ctx_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - _sgl_draw(ctx, 0); - } -} - -SOKOL_API_IMPL void sgl_context_draw_layer(sgl_context ctx_id, int layer_id) { - SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); - _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); - if (ctx) { - _sgl_draw(ctx, layer_id); - } -} - -#endif /* SOKOL_GL_IMPL */ diff --git a/source/thirdparty/sokol/util/sokol_imgui.h b/source/thirdparty/sokol/util/sokol_imgui.h deleted file mode 100644 index 3d0a5af5..00000000 --- a/source/thirdparty/sokol/util/sokol_imgui.h +++ /dev/null @@ -1,3151 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_IMGUI_IMPL) -#define SOKOL_IMGUI_IMPL -#endif -#ifndef SOKOL_IMGUI_INCLUDED -/* - sokol_imgui.h -- drop-in Dear ImGui renderer/event-handler for sokol_gfx.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_IMGUI_IMPL - - before you include this file in *one* C or C++ file to create the - implementation. - - NOTE that the implementation can be compiled either as C++ or as C. - When compiled as C++, sokol_imgui.h will directly call into the - Dear ImGui C++ API. When compiled as C, sokol_imgui.h will call - cimgui.h functions instead. - - NOTE that the formerly separate header sokol_cimgui.h has been - merged into sokol_imgui.h - - 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 configuration define both before including the - the declaration and implementation: - - SOKOL_IMGUI_NO_SOKOL_APP - don't depend on sokol_app.h (see below for details) - - Optionally provide the following macros before including the implementation - to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_IMGUI_API_DECL- public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_IMGUI_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_imgui.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_IMGUI_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - Include the following headers before sokol_imgui.h (both before including - the declaration and implementation): - - sokol_gfx.h - sokol_app.h (except SOKOL_IMGUI_NO_SOKOL_APP) - - Additionally, include the following headers before including the - implementation: - - If the implementation is compiled as C++: - imgui.h - - If the implementation is compiled as C: - cimgui.h - - - FEATURE OVERVIEW: - ================= - sokol_imgui.h implements the initialization, rendering and event-handling - code for Dear ImGui (https://github.com/ocornut/imgui) on top of - sokol_gfx.h and (optionally) sokol_app.h. - - The sokol_app.h dependency is optional and used for input event handling. - If you only use sokol_gfx.h but not sokol_app.h in your application, - define SOKOL_IMGUI_NO_SOKOL_APP before including the implementation - of sokol_imgui.h, this will remove any dependency to sokol_app.h, but - you must feed input events into Dear ImGui yourself. - - sokol_imgui.h is not thread-safe, all calls must be made from the - same thread where sokol_gfx.h is running. - - HOWTO: - ====== - - --- To initialize sokol-imgui, call: - - simgui_setup(const simgui_desc_t* desc) - - This will initialize Dear ImGui and create sokol-gfx resources - (two buffers for vertices and indices, a font texture and a pipeline- - state-object). - - Use the following simgui_desc_t members to configure behaviour: - - int max_vertices - The maximum number of vertices used for UI rendering, default is 65536. - sokol-imgui will use this to compute the size of the vertex- - and index-buffers allocated via sokol_gfx.h - - int image_pool_size - Number of simgui_image_t objects which can be alive at the same time. - The default is 256. - - sg_pixel_format color_format - The color pixel format of the render pass where the UI - will be rendered. The default (0) matches sokoL_gfx.h's - default pass. - - sg_pixel_format depth_format - The depth-buffer pixel format of the render pass where - the UI will be rendered. The default (0) matches - sokol_gfx.h's default pass depth format. - - int sample_count - The MSAA sample-count of the render pass where the UI - will be rendered. The default (0) matches sokol_gfx.h's - default pass sample count. - - const char* ini_filename - Sets this path as ImGui::GetIO().IniFilename where ImGui will store - and load UI persistency data. By default this is 0, so that Dear ImGui - will not preserve state between sessions (and also won't do - any filesystem calls). Also see the ImGui functions: - - LoadIniSettingsFromMemory() - - SaveIniSettingsFromMemory() - These functions give you explicit control over loading and saving - UI state while using your own filesystem wrapper functions (in this - case keep simgui_desc.ini_filename zero) - - bool no_default_font - Set this to true if you don't want to use ImGui's default - font. In this case you need to initialize the font - yourself after simgui_setup() is called. - - bool disable_paste_override - If set to true, sokol_imgui.h will not 'emulate' a Dear Imgui - clipboard paste action on SAPP_EVENTTYPE_CLIPBOARD_PASTED event. - This is mainly a hack/workaround to allow external workarounds - for making copy/paste work on the web platform. In general, - copy/paste support isn't properly fleshed out in sokol_imgui.h yet. - - bool disable_set_mouse_cursor - If true, sokol_imgui.h will not control the mouse cursor type - by calling sapp_set_mouse_cursor(). - - bool disable_windows_resize_from_edges - If true, windows can only be resized from the bottom right corner. - The default is false, meaning windows can be resized from edges. - - bool write_alpha_channel - Set this to true if you want alpha values written to the - framebuffer. By default this behavior is disabled to prevent - undesired behavior on platforms like the web where the canvas is - always alpha-blended with the background. - - simgui_allocator_t allocator - Used to override memory allocation functions. See further below - for details. - - simgui_logger_t logger - A user-provided logging callback. Note that without logging - callback, sokol-imgui will be completely silent! - See the section about ERROR REPORTING AND LOGGING below - for more details. - - --- At the start of a frame, call: - - simgui_new_frame(&(simgui_frame_desc_t){ - .width = ..., - .height = ..., - .delta_time = ..., - .dpi_scale = ... - }); - - 'width' and 'height' are the dimensions of the rendering surface, - passed to ImGui::GetIO().DisplaySize. - - 'delta_time' is the frame duration passed to ImGui::GetIO().DeltaTime. - - 'dpi_scale' is the current DPI scale factor, if this is left zero-initialized, - 1.0f will be used instead. Typical values for dpi_scale are >= 1.0f. - - For example, if you're using sokol_app.h and render to the default framebuffer: - - simgui_new_frame(&(simgui_frame_desc_t){ - .width = sapp_width(), - .height = sapp_height(), - .delta_time = sapp_frame_duration(), - .dpi_scale = sapp_dpi_scale() - }); - - --- at the end of the frame, before the sg_end_pass() where you - want to render the UI, call: - - simgui_render() - - This will first call ImGui::Render(), and then render ImGui's draw list - through sokol_gfx.h - - --- if you're using sokol_app.h, from inside the sokol_app.h event callback, - call: - - bool simgui_handle_event(const sapp_event* ev); - - The return value is the value of ImGui::GetIO().WantCaptureKeyboard, - if this is true, you might want to skip keyboard input handling - in your own event handler. - - If you want to use the ImGui functions for checking if a key is pressed - (e.g. ImGui::IsKeyPressed()) the following helper function to map - an sapp_keycode to an ImGuiKey value may be useful: - - int simgui_map_keycode(sapp_keycode c); - - Note that simgui_map_keycode() can be called outside simgui_setup()/simgui_shutdown(). - - --- finally, on application shutdown, call - - simgui_shutdown() - - - ON USER-PROVIDED IMAGES AND SAMPLERS - ==================================== - To render your own images via ImGui::Image(), first create an simgui_image_t - object from a sokol-gfx image and sampler object. - - // create a sokol-imgui image object which associates an sg_image with an sg_sampler - simgui_image_t simgui_img = simgui_make_image(&(simgui_image_desc_t){ - .image = sg_make_image(...), - .sampler = sg_make_sampler(...), - }); - - // convert the returned image handle into a ImTextureID handle - ImTextureID tex_id = simgui_imtextureid(simgui_img); - - // use the ImTextureID handle in Dear ImGui calls: - ImGui::Image(tex_id, ...); - - simgui_image_t objects are small and cheap (literally just the image and sampler - handle). - - You can omit the sampler handle in the simgui_make_image() call, in this case a - default sampler will be used with nearest-filtering and clamp-to-edge. - - Trying to render with an invalid simgui_image_t handle will render a small 8x8 - white default texture instead. - - To destroy a sokol-imgui image object, call - - simgui_destroy_image(simgui_img); - - But please be aware that the image object needs to be around until simgui_render() is called - in a frame (if this turns out to be too much of a hassle we could introduce some sort - of garbage collection where destroyed simgui_image_t objects are kept around until - the simgui_render() call). - - You can call: - - simgui_image_desc_t desc = simgui_query_image_desc(img) - - ...to get the original desc struct, useful if you need to get the sokol-gfx image - and sampler handle of the simgui_image_t object. - - You can convert an ImTextureID back into an simgui_image_t handle: - - simgui_image_t img = simgui_image_from_imtextureid(tex_id); - - - 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); - } - - ... - simgui_setup(&(simgui_desc_t){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ...; - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_imgui.h - itself though, not any allocations in Dear ImGui. - - - 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" - - simgui_setup(&(simgui_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. 'simgui' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SIMGUI_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_imgui.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-imgui like this: - - simgui_setup(&(simgui_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. - - - IMGUI EVENT HANDLING - ==================== - You can call these functions from your platform's events to handle ImGui events - when SOKOL_IMGUI_NO_SOKOL_APP is defined. - - E.g. mouse position events can be dispatched like this: - - simgui_add_mouse_pos_event(100, 200); - - For adding key events, you're responsible to map your own key codes to ImGuiKey - values and pass those as int: - - simgui_add_key_event(imgui_key, true); - - Take note that modifiers (shift, ctrl, etc.) must be updated manually. - - If sokol_app is being used, ImGui events are handled for you. - - - 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. -*/ -#define SOKOL_IMGUI_INCLUDED (1) -#include -#include -#include // size_t - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_imgui.h" -#endif -#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) && !defined(SOKOL_APP_INCLUDED) -#error "Please include sokol_app.h before sokol_imgui.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_IMGUI_API_DECL) -#define SOKOL_IMGUI_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_IMGUI_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMGUI_IMPL) -#define SOKOL_IMGUI_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_IMGUI_API_DECL __declspec(dllimport) -#else -#define SOKOL_IMGUI_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - SIMGUI_INVALID_ID = 0, -}; - -/* - simgui_image_t - - A combined image-sampler pair used to inject custom images and samplers into Dear ImGui. - - Create with simgui_make_image(), and convert to an ImTextureID handle via - simgui_imtextureid(). -*/ -typedef struct simgui_image_t { uint32_t id; } simgui_image_t; - -/* - simgui_image_desc_t - - Descriptor struct for simgui_make_image(). You must provide - at least an sg_image handle. Keeping the sg_sampler handle - zero-initialized will select the builtin default sampler - which uses linear filtering. -*/ -typedef struct simgui_image_desc_t { - sg_image image; - sg_sampler sampler; -} simgui_image_desc_t; - -/* - simgui_log_item - - An enum with a unique item for each log message, warning, error - and validation layer message. -*/ -#define _SIMGUI_LOG_ITEMS \ - _SIMGUI_LOGITEM_XMACRO(OK, "Ok") \ - _SIMGUI_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SIMGUI_LOGITEM_XMACRO(IMAGE_POOL_EXHAUSTED, "image pool exhausted") \ - -#define _SIMGUI_LOGITEM_XMACRO(item,msg) SIMGUI_LOGITEM_##item, -typedef enum simgui_log_item_t { - _SIMGUI_LOG_ITEMS -} simgui_log_item_t; -#undef _SIMGUI_LOGITEM_XMACRO - -/* - simgui_allocator_t - - Used in simgui_desc_t to provide custom memory-alloc and -free functions - to sokol_imgui.h. If memory management should be overridden, both the - alloc_fn and free_fn function must be provided (e.g. it's not valid to - override one function but not the other). -*/ -typedef struct simgui_allocator_t { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} simgui_allocator_t; - -/* - simgui_logger - - Used in simgui_desc_t to provide a logging function. Please be aware - that without logging function, sokol-imgui will be completely - silent, e.g. it will not report errors, warnings and - validation layer messages. For maximum error verbosity, - compile in debug mode (e.g. NDEBUG *not* defined) and install - a logger (for instance the standard logging function from sokol_log.h). -*/ -typedef struct simgui_logger_t { - void (*func)( - const char* tag, // always "simgui" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SIMGUI_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_imgui.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} simgui_logger_t; - -typedef struct simgui_desc_t { - int max_vertices; // default: 65536 - int image_pool_size; // default: 256 - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - const char* ini_filename; - bool no_default_font; - bool disable_paste_override; // if true, don't send Ctrl-V on EVENTTYPE_CLIPBOARD_PASTED - bool disable_set_mouse_cursor; // if true, don't control the mouse cursor type via sapp_set_mouse_cursor() - bool disable_windows_resize_from_edges; // if true, only resize edges from the bottom right corner - bool write_alpha_channel; // if true, alpha values get written into the framebuffer - simgui_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) - simgui_logger_t logger; // optional log function override -} simgui_desc_t; - -typedef struct simgui_frame_desc_t { - int width; - int height; - double delta_time; - float dpi_scale; -} simgui_frame_desc_t; - -typedef struct simgui_font_tex_desc_t { - sg_filter min_filter; - sg_filter mag_filter; -} simgui_font_tex_desc_t; - -SOKOL_IMGUI_API_DECL void simgui_setup(const simgui_desc_t* desc); -SOKOL_IMGUI_API_DECL void simgui_new_frame(const simgui_frame_desc_t* desc); -SOKOL_IMGUI_API_DECL void simgui_render(void); -SOKOL_IMGUI_API_DECL simgui_image_t simgui_make_image(const simgui_image_desc_t* desc); -SOKOL_IMGUI_API_DECL void simgui_destroy_image(simgui_image_t img); -SOKOL_IMGUI_API_DECL simgui_image_desc_t simgui_query_image_desc(simgui_image_t img); -SOKOL_IMGUI_API_DECL void* simgui_imtextureid(simgui_image_t img); -SOKOL_IMGUI_API_DECL simgui_image_t simgui_image_from_imtextureid(void* im_texture_id); -SOKOL_IMGUI_API_DECL void simgui_add_focus_event(bool focus); -SOKOL_IMGUI_API_DECL void simgui_add_mouse_pos_event(float x, float y); -SOKOL_IMGUI_API_DECL void simgui_add_touch_pos_event(float x, float y); -SOKOL_IMGUI_API_DECL void simgui_add_mouse_button_event(int mouse_button, bool down); -SOKOL_IMGUI_API_DECL void simgui_add_mouse_wheel_event(float wheel_x, float wheel_y); -SOKOL_IMGUI_API_DECL void simgui_add_key_event(int imgui_key, bool down); -SOKOL_IMGUI_API_DECL void simgui_add_input_character(uint32_t c); -SOKOL_IMGUI_API_DECL void simgui_add_input_characters_utf8(const char* c); -SOKOL_IMGUI_API_DECL void simgui_add_touch_button_event(int mouse_button, bool down); -#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) -SOKOL_IMGUI_API_DECL bool simgui_handle_event(const sapp_event* ev); -SOKOL_IMGUI_API_DECL int simgui_map_keycode(sapp_keycode keycode); // returns ImGuiKey_* -#endif -SOKOL_IMGUI_API_DECL void simgui_shutdown(void); -SOKOL_IMGUI_API_DECL void simgui_create_fonts_texture(const simgui_font_tex_desc_t* desc); -SOKOL_IMGUI_API_DECL void simgui_destroy_fonts_texture(void); - -#ifdef __cplusplus -} // extern "C" - -// reference-based equivalents for C++ -inline void simgui_setup(const simgui_desc_t& desc) { return simgui_setup(&desc); } -inline simgui_image_t simgui_make_image(const simgui_image_desc_t& desc) { return simgui_make_image(&desc); } -inline void simgui_new_frame(const simgui_frame_desc_t& desc) { return simgui_new_frame(&desc); } -inline void simgui_create_fonts_texture(const simgui_font_tex_desc_t& desc) { return simgui_create_fonts_texture(&desc); } - -#endif -#endif /* SOKOL_IMGUI_INCLUDED */ - -//-- IMPLEMENTATION ------------------------------------------------------------ -#ifdef SOKOL_IMGUI_IMPL -#define SOKOL_IMGUI_IMPL_INCLUDED (1) - -#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) -#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use simgui_desc_t.allocator to override memory allocation functions" -#endif - -#if defined(__cplusplus) - #if !defined(IMGUI_VERSION) - #error "Please include imgui.h before the sokol_imgui.h implementation" - #endif -#else - #if !defined(CIMGUI_INCLUDED) - #error "Please include cimgui.h before the sokol_imgui.h implementation" - #endif -#endif - -#include // memset -#include // malloc/free - -#if defined(__EMSCRIPTEN__) && !defined(SOKOL_DUMMY_BACKEND) -#include -#endif - -#ifndef SOKOL_API_IMPL -#define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -#define _SIMGUI_INIT_COOKIE (0xBABEBABE) -#define _SIMGUI_INVALID_SLOT_INDEX (0) -#define _SIMGUI_SLOT_SHIFT (16) -#define _SIMGUI_MAX_POOL_SIZE (1<<_SIMGUI_SLOT_SHIFT) -#define _SIMGUI_SLOT_MASK (_SIMGUI_MAX_POOL_SIZE-1) - -// helper macros and constants -#define _simgui_def(val, def) (((val) == 0) ? (def) : (val)) - -// workaround for missing ImDrawCallback_ResetRenderState in cimgui.h -// see: https://github.com/cimgui/cimgui/issues/261 -#ifndef ImDrawCallback_ResetRenderState -#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) -#endif - -typedef struct { - ImVec2 disp_size; - uint8_t _pad_8[8]; -} _simgui_vs_params_t; - -typedef enum { - _SIMGUI_RESOURCESTATE_INITIAL, - _SIMGUI_RESOURCESTATE_ALLOC, - _SIMGUI_RESOURCESTATE_VALID, - _SIMGUI_RESOURCESTATE_FAILED, - _SIMGUI_RESOURCESTATE_INVALID, - _SIMGUI_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF -} _simgui_resource_state; - -typedef struct { - uint32_t id; - _simgui_resource_state state; -} _simgui_slot_t; - -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _simgui_pool_t; - -typedef struct { - _simgui_slot_t slot; - sg_image image; - sg_sampler sampler; - sg_pipeline pip; // this will either be _simgui.def_pip or _simgui.pip_unfilterable -} _simgui_image_t; - -typedef struct { - _simgui_pool_t pool; - _simgui_image_t* items; -} _simgui_image_pool_t; - -typedef struct { - uint32_t init_cookie; - simgui_desc_t desc; - float cur_dpi_scale; - sg_buffer vbuf; - sg_buffer ibuf; - sg_image font_img; - sg_sampler font_smp; - simgui_image_t default_font; - sg_image def_img; // used as default image for user images - sg_sampler def_smp; // used as default sampler for user images - sg_shader def_shd; - sg_pipeline def_pip; - // separate shader and pipeline for unfilterable user images - sg_shader shd_unfilterable; - sg_pipeline pip_unfilterable; - sg_range vertices; - sg_range indices; - bool is_osx; - _simgui_image_pool_t image_pool; -} _simgui_state_t; -static _simgui_state_t _simgui; - -/* - Embedded source code compiled with: - - sokol-shdc -i simgui.glsl -o simgui.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgpu -b - - (not that for Metal and D3D11 byte code, sokol-shdc must be run - on macOS and Windows) - - @vs vs - uniform vs_params { - vec2 disp_size; - }; - in vec2 position; - in vec2 texcoord0; - in vec4 color0; - out vec2 uv; - out vec4 color; - void main() { - gl_Position = vec4(((position/disp_size)-0.5)*vec2(2.0,-2.0), 0.5, 1.0); - uv = texcoord0; - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - in vec2 uv; - in vec4 color; - out vec4 frag_color; - void main() { - frag_color = texture(sampler2D(tex, smp), uv) * color; - } - @end - - @program simgui vs fs -*/ -#if defined(SOKOL_GLCORE) -static const uint8_t _simgui_vs_source_glsl410[383] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, - 0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76, - 0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c, - 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, - 0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29, - 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x28,0x28,0x70,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73, - 0x5b,0x30,0x5d,0x2e,0x78,0x79,0x29,0x20,0x2d,0x20,0x76,0x65,0x63,0x32,0x28,0x30, - 0x2e,0x35,0x29,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x32,0x28,0x32,0x2e,0x30,0x2c, - 0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e,0x35,0x2c,0x20,0x31,0x2e,0x30, - 0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x74,0x65,0x78,0x63, - 0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _simgui_fs_source_glsl410[219] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, - 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32, - 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, - 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67, - 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65, - 0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x29,0x20,0x2a,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_GLES3) -static const uint8_t _simgui_vs_source_glsl300es[344] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, - 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, - 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20, - 0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f, - 0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65, - 0x63,0x34,0x28,0x28,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x79,0x29, - 0x20,0x2d,0x20,0x76,0x65,0x63,0x32,0x28,0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20, - 0x76,0x65,0x63,0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c, - 0x20,0x30,0x2e,0x35,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x75,0x76,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _simgui_fs_source_glsl300es[250] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a, - 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20, - 0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x75, - 0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, - 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, - 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x29,0x20,0x2a,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _simgui_vs_bytecode_metal_macos[3052] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x7b,0x12,0x23,0x17,0xd9,0x25,0x1c, - 0x1b,0x42,0x42,0x9f,0xbf,0x31,0xd2,0x2c,0x3a,0x55,0x22,0x1d,0x40,0xd8,0xc4,0xf8, - 0x20,0x49,0x60,0x6d,0x3c,0xea,0x4e,0x1c,0x34,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xc8,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xaf,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x81,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x18,0x02,0x01,0x2c,0x40,0x05,0x00,0x49,0x18,0x00,0x00, - 0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00,0x16,0x00,0x00,0x00, - 0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04,0x13,0x22,0xa4,0x84,0x04,0x13,0x22,0xe3, - 0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c,0x0b,0x84,0x84,0x4c,0x10,0x3c,0x33,0x00, - 0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x91,0x83,0xa4,0x29,0xa2,0x84,0xc9, - 0xaf,0xa4,0xff,0x01,0x22,0x80,0x91,0x50,0x10,0x83,0x08,0x84,0x50,0x8a,0x89,0x90, - 0x22,0x1b,0x08,0x98,0x23,0x00,0x83,0x14,0xc8,0x39,0x02,0x50,0x18,0x44,0x08,0x84, - 0x61,0x04,0x22,0x19,0x01,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0,0x03, - 0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87,0x71, - 0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38,0xd8, - 0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06, - 0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07,0x7a, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07, - 0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07, - 0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20, - 0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d, - 0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80, - 0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07, - 0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07,0x75, - 0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76,0xa0, - 0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50,0x07, - 0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x6d, - 0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xa0, - 0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60,0x07, - 0x7a,0x30,0x07,0x72,0x30,0x84,0x39,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0xc8, - 0x02,0x01,0x00,0x00,0x09,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90, - 0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0xca,0x12,0x18,0x01,0x28,0x88,0x22,0x28,0x84, - 0x32,0xa0,0x1d,0x01,0x20,0x1d,0x4b,0x68,0x02,0x00,0x00,0x00,0x79,0x18,0x00,0x00, - 0xea,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9, - 0xb9,0xb4,0x37,0xb7,0x21,0x46,0x42,0x20,0x80,0x82,0x50,0xb9,0x1b,0x43,0x0b,0x93, - 0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x24,0x01,0x22,0x24,0x05,0xe7,0x20,0x08,0x0e, - 0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd, - 0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e, - 0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26, - 0x65,0x88,0x80,0x10,0x43,0x8c,0x24,0x48,0x86,0x44,0x60,0xd1,0x54,0x46,0x17,0xc6, - 0x36,0x04,0x41,0x8e,0x24,0x48,0x82,0x44,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6, - 0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36, - 0x17,0x26,0xc6,0x56,0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d, - 0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65, - 0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x64,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd, - 0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95, - 0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d, - 0x11,0x90,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b, - 0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98, - 0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e, - 0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84, - 0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20,0x0f,0x02,0x21, - 0x11,0x22,0x21,0x13,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b, - 0x49,0xa1,0x61,0xc6,0xf6,0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08, - 0x83,0x3c,0x88,0x85,0x44,0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee, - 0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d, - 0xda,0x9b,0xdb,0x10,0x05,0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86,0x18,0x48,0x85, - 0x64,0x08,0x47,0x28,0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd, - 0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b, - 0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32, - 0x32,0x94,0xaf,0xaf,0xb0,0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36, - 0xb2,0x32,0xb9,0xaf,0xaf,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43, - 0xa8,0x44,0x40,0x3c,0xe4,0x4b,0x84,0x24,0x40,0xc0,0x00,0x89,0x10,0x09,0x99,0x90, - 0x30,0x60,0x42,0x57,0x86,0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84,0x4a,0x02,0xc4, - 0x43,0xbe,0x24,0x48,0x02,0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19,0x03,0x1a,0x63, - 0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88,0x24,0x40,0xc0, - 0x00,0x89,0x90,0x0b,0x99,0x90,0x32,0xa0,0x12,0x96,0x26,0xe7,0x22,0x56,0x67,0x66, - 0x56,0x26,0xc7,0x27,0x2c,0x4d,0xce,0x45,0xac,0xce,0xcc,0xac,0x4c,0xee,0x6b,0x2e, - 0x4d,0xaf,0x8c,0x48,0x58,0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39, - 0x97,0x39,0x3a,0xb9,0xba,0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3, - 0x37,0x26,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x43,0x94,0x44,0x48,0x86, - 0x44,0x40,0x24,0x64,0x0d,0x18,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5, - 0xc1,0x95,0x7d,0xcd,0xa5,0xe9,0x95,0xf1,0x0a,0x4b,0x93,0x73,0x09,0x93,0x3b,0xfb, - 0xa2,0xcb,0x83,0x2b,0xfb,0x0a,0x63,0x4b,0x3b,0x73,0xfb,0x9a,0x4b,0xd3,0x2b,0x63, - 0x62,0x37,0xf7,0x05,0x17,0x26,0x17,0xd6,0x36,0xc7,0xe1,0x4b,0x46,0x66,0x08,0x19, - 0x24,0x06,0x72,0x06,0x08,0x1a,0x24,0x03,0xf2,0x25,0x42,0x12,0x20,0x69,0x80,0xa8, - 0x01,0xc2,0x06,0x48,0x1b,0x24,0x03,0xe2,0x06,0xc9,0x80,0x44,0xc8,0x1b,0x20,0x13, - 0x02,0x07,0x43,0x10,0x44,0x0c,0x10,0x32,0x40,0xcc,0x00,0x89,0x83,0x21,0xc6,0x01, - 0x20,0x1d,0x22,0x07,0x7c,0xde,0xda,0xdc,0xd2,0xe0,0xde,0xe8,0xca,0xdc,0xe8,0x40, - 0xc6,0xd0,0xc2,0xe4,0xf8,0x4c,0xa5,0xb5,0xc1,0xb1,0x95,0x81,0x0c,0xad,0xac,0x80, - 0x50,0x09,0x05,0x05,0x0d,0x11,0x90,0x3a,0x18,0x62,0x20,0x74,0x80,0xd8,0xc1,0x72, - 0x0c,0x31,0x90,0x3b,0x40,0xee,0x60,0x39,0x46,0x44,0xec,0xc0,0x0e,0xf6,0xd0,0x0e, - 0x6e,0xd0,0x0e,0xef,0x40,0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0,0x0e,0xe1, - 0x70,0x0e,0xf3,0x30,0x45,0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b, - 0xa4,0x03,0x39,0x94,0x83,0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43,0x3a,0xc8, - 0x83,0x1b,0xd8,0x43,0x39,0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94,0xc0,0x18, - 0x41,0x85,0x43,0x3a,0xc8,0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4,0x43,0x38, - 0x9c,0x43,0x39,0xfc,0x82,0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83,0x3b,0x4c, - 0x09,0x90,0x11,0x53,0x38,0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b,0xc0,0x43, - 0x3a,0xb0,0x43,0x39,0xfc,0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x3c, - 0x4c,0x19,0x14,0xc6,0x19,0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8, - 0x03,0x3d,0x94,0x03,0x3e,0x4c,0x09,0xe6,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00, - 0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88, - 0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6, - 0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce, - 0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8, - 0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48, - 0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11, - 0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e, - 0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89, - 0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b, - 0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37, - 0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78, - 0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81, - 0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1, - 0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c, - 0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39, - 0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc, - 0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58, - 0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87, - 0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f, - 0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e, - 0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66, - 0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0, - 0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e, - 0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc, - 0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3, - 0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07, - 0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e, - 0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e, - 0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d, - 0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00, - 0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00, - 0x61,0x20,0x00,0x00,0x23,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00, - 0x11,0x00,0x00,0x00,0xd4,0x63,0x11,0x40,0x60,0x1c,0x73,0x10,0x42,0xf0,0x3c,0x94, - 0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82,0xf0,0x2f,0x80,0x20,0x08,0xc2,0xbf,0x30, - 0x96,0x00,0x82,0x20,0x08,0x82,0x01,0x08,0x82,0x20,0x08,0x0e,0x33,0x00,0x24,0x73, - 0x10,0xd7,0x65,0x55,0x34,0x33,0x00,0x04,0x63,0x04,0x20,0x08,0x82,0xf8,0x37,0x46, - 0x00,0x82,0x20,0x08,0x7f,0x33,0x00,0x00,0xe3,0x0d,0x4c,0x64,0x51,0x40,0x2c,0x0a, - 0xe8,0x63,0xc1,0x02,0x1f,0x0b,0x16,0xf9,0x0c,0x32,0x04,0xcb,0x33,0xc8,0x10,0x2c, - 0xd1,0x6c,0xc3,0x52,0x01,0xb3,0x0d,0x41,0x15,0xcc,0x36,0x04,0x83,0x90,0x41,0x40, - 0x0c,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5b,0x86,0x20,0xc0,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _simgui_fs_bytecode_metal_macos[2809] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf9,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x20,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xa1,0xce,0x6b,0xd1,0x1f,0x32,0x9e, - 0x8d,0x8d,0x1c,0xcc,0x19,0xcb,0xd3,0xb6,0x21,0x99,0x0b,0xb6,0x46,0x8b,0x87,0x98, - 0x8e,0x2d,0xb5,0x98,0x92,0x0a,0x81,0x7d,0xf3,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x0c,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x80,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, - 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, - 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, - 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, - 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, - 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, - 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, - 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, - 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, - 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, - 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64,0x81,0x00,0x00,0x00, - 0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, - 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70, - 0x2c,0xa1,0x09,0x00,0x00,0x79,0x18,0x00,0x00,0xb9,0x00,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42, - 0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45, - 0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84, - 0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84, - 0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c, - 0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0, - 0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32, - 0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe, - 0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d, - 0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9,0x99,0x86,0x08,0x0f,0x45,0x29,0x2c, - 0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e, - 0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34, - 0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72, - 0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28, - 0xd4,0xd9,0x0d,0x91,0x96,0xe1,0xb1,0x9e,0xeb,0xc1,0x9e,0xec,0x81,0x1e,0xed,0x91, - 0x9e,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1, - 0x37,0xb6,0x37,0xb9,0x21,0xd2,0x22,0x3c,0xd6,0xd3,0x3d,0xd8,0x93,0x3d,0xd0,0x13, - 0x3d,0xd2,0xe3,0x71,0x09,0x4b,0x93,0x73,0xa1,0x2b,0xc3,0xa3,0xab,0x93,0x2b,0xa3, - 0x14,0x96,0x26,0xe7,0xc2,0xf6,0x36,0x16,0x46,0x97,0xf6,0xe6,0xf6,0x95,0xe6,0x46, - 0x56,0x86,0x47,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x8c,0x18,0x5d, - 0x19,0x1e,0x5d,0x9d,0x5c,0x99,0x0c,0x19,0x8f,0x19,0xdb,0x5b,0x18,0x1d,0x0b,0xc8, - 0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x0f,0x07,0xba,0x32,0xbc,0x21,0xd4,0x42,0x3c,0x60, - 0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x23,0x06,0x0f,0xf4,0x8c,0xc1,0x23,0x3d,0x64,0xc0, - 0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e,0xad,0x4c,0x8e,0xc7,0x5c,0x58,0x1b, - 0x1c,0x5b,0x99,0x1c,0x87,0xb9,0x36,0xb8,0x21,0xd2,0x72,0x3c,0x66,0xf0,0x84,0xc1, - 0x32,0x2c,0xc2,0x03,0x3d,0x67,0xf0,0x48,0x0f,0x1a,0x0c,0x41,0x1e,0xee,0xf9,0x9e, - 0x32,0x78,0xd2,0x60,0x88,0x91,0x00,0x4f,0xf5,0xa8,0xc1,0x88,0x88,0x1d,0xd8,0xc1, - 0x1e,0xda,0xc1,0x0d,0xda,0xe1,0x1d,0xc8,0xa1,0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c, - 0xd8,0x21,0x1c,0xce,0x61,0x1e,0xa6,0x08,0xc1,0x30,0x42,0x61,0x07,0x76,0xb0,0x87, - 0x76,0x70,0x83,0x74,0x20,0x87,0x72,0x70,0x07,0x7a,0x98,0x12,0x14,0x23,0x96,0x70, - 0x48,0x07,0x79,0x70,0x03,0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78,0x07,0x77,0x98, - 0x12,0x18,0x23,0xa8,0x70,0x48,0x07,0x79,0x70,0x03,0x76,0x08,0x07,0x77,0x38,0x87, - 0x7a,0x08,0x87,0x73,0x28,0x87,0x5f,0xb0,0x87,0x72,0x90,0x87,0x79,0x48,0x87,0x77, - 0x70,0x87,0x29,0x01,0x32,0x62,0x0a,0x87,0x74,0x90,0x07,0x37,0x18,0x87,0x77,0x68, - 0x07,0x78,0x48,0x07,0x76,0x28,0x87,0x5f,0x78,0x07,0x78,0xa0,0x87,0x74,0x78,0x07, - 0x77,0x98,0x87,0x29,0x83,0xc2,0x38,0x23,0x98,0x70,0x48,0x07,0x79,0x70,0x03,0x73, - 0x90,0x87,0x70,0x38,0x87,0x76,0x28,0x07,0x77,0xa0,0x87,0x29,0xc1,0x1a,0x00,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01, - 0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e, - 0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00, - 0x00,0x0c,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x04,0x00,0x00, - 0x00,0xc4,0x46,0x00,0x48,0x8d,0x00,0xd4,0x00,0x89,0x19,0x00,0x02,0x23,0x00,0x00, - 0x00,0x23,0x06,0x8a,0x10,0x44,0x87,0x91,0x0c,0x05,0x11,0x58,0x90,0xc8,0x67,0xb6, - 0x81,0x08,0x80,0x0c,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _simgui_vs_bytecode_metal_ios[3052] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xec,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x69,0x97,0x6b,0xac,0xd8,0xa2,0x51, - 0x33,0x7c,0x5f,0x96,0xb2,0xb1,0x06,0x06,0x7c,0xbb,0x5f,0x88,0xa0,0xeb,0x9f,0xea, - 0x6e,0x6b,0x70,0xa9,0x6e,0xef,0xe6,0xa4,0xea,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xc0,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xad,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x20,0x02,0x01,0x24,0xc0,0x02,0x54,0x00,0x00,0x00,0x00, - 0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00, - 0x16,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04,0x13,0x22,0xa4,0x84, - 0x04,0x13,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c,0x0b,0x84,0x84,0x4c, - 0x10,0x3c,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x91,0x83,0xa4, - 0x29,0xa2,0x84,0xc9,0xaf,0xa4,0xff,0x01,0x22,0x80,0x91,0x50,0x10,0x83,0x08,0x84, - 0x50,0x8a,0x89,0x90,0x22,0x1b,0x08,0x98,0x23,0x00,0x83,0x14,0xc8,0x39,0x02,0x50, - 0x18,0x44,0x08,0x84,0x61,0x04,0x22,0x19,0x01,0x00,0x00,0x00,0x13,0xa8,0x70,0x48, - 0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83, - 0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e, - 0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0, - 0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07, - 0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a, - 0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60, - 0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0, - 0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6, - 0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07, - 0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6, - 0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80, - 0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07, - 0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75, - 0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0, - 0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07, - 0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70, - 0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20, - 0x07,0x43,0x98,0x03,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x2c,0x10,0x00,0x00, - 0x09,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47, - 0xc6,0x04,0x43,0xca,0x12,0x18,0x01,0x28,0x88,0x22,0x28,0x84,0x32,0xa0,0x1d,0x01, - 0x20,0x1d,0x4b,0x80,0x04,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xe9,0x00,0x00,0x00, - 0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7, - 0x21,0x46,0x42,0x20,0x80,0x82,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3, - 0x2b,0x1b,0x62,0x24,0x01,0x22,0x24,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4, - 0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac, - 0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0x80,0x10, - 0x43,0x8c,0x24,0x48,0x86,0x44,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x41,0x8e, - 0x24,0x48,0x82,0x44,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56, - 0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56, - 0x36,0x44,0x40,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65, - 0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c, - 0x65,0x43,0x04,0x64,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1, - 0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95, - 0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d,0x11,0x90,0x86,0x51,0x58, - 0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d, - 0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72, - 0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc, - 0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85, - 0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x20,0x0f,0x02,0x21,0x11,0x22,0x21,0x13,0x42, - 0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6,0xf6, - 0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08,0x83,0x3c,0x88,0x85,0x44, - 0xc8,0x85,0x4c,0x08,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e,0xed, - 0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10,0x05, - 0xd1,0x90,0x08,0xb9,0x90,0x09,0xd9,0x86,0x18,0x48,0x85,0x64,0x08,0x47,0x28,0x2c, - 0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52, - 0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59, - 0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32,0x32,0x94,0xaf,0xaf,0xb0, - 0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf,0xaf, - 0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43,0xa8,0x44,0x40,0x3c,0xe4, - 0x4b,0x84,0x24,0x40,0xc0,0x00,0x89,0x10,0x09,0x99,0x90,0x30,0x60,0x42,0x57,0x86, - 0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84,0x4a,0x02,0xc4,0x43,0xbe,0x24,0x48,0x02, - 0x04,0x0c,0x90,0x08,0x91,0x90,0x09,0x19,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30, - 0x43,0xa8,0x84,0x40,0x3c,0xe4,0x4b,0x88,0x24,0x40,0xc0,0x00,0x89,0x90,0x0b,0x99, - 0x90,0x32,0xa0,0x12,0x96,0x26,0xe7,0x22,0x56,0x67,0x66,0x56,0x26,0xc7,0x27,0x2c, - 0x4d,0xce,0x45,0xac,0xce,0xcc,0xac,0x4c,0xee,0x6b,0x2e,0x4d,0xaf,0x8c,0x48,0x58, - 0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39,0x97,0x39,0x3a,0xb9,0xba, - 0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3,0x37,0x26,0x64,0x69,0x73, - 0x70,0x5f,0x73,0x69,0x7a,0x65,0x43,0x94,0x44,0x48,0x86,0x44,0x40,0x24,0x64,0x0d, - 0x18,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5,0xc1,0x95,0x7d,0xcd,0xa5, - 0xe9,0x95,0xf1,0x0a,0x4b,0x93,0x73,0x09,0x93,0x3b,0xfb,0xa2,0xcb,0x83,0x2b,0xfb, - 0x0a,0x63,0x4b,0x3b,0x73,0xfb,0x9a,0x4b,0xd3,0x2b,0x63,0x62,0x37,0xf7,0x05,0x17, - 0x26,0x17,0xd6,0x36,0xc7,0xe1,0x4b,0x46,0x66,0x08,0x19,0x24,0x06,0x72,0x06,0x08, - 0x1a,0x24,0x03,0xf2,0x25,0x42,0x12,0x20,0x69,0x80,0xa8,0x01,0xc2,0x06,0x48,0x1b, - 0x24,0x03,0xe2,0x06,0xc9,0x80,0x44,0xc8,0x1b,0x20,0x13,0x02,0x07,0x43,0x10,0x44, - 0x0c,0x10,0x32,0x40,0xcc,0x00,0x89,0x83,0x21,0xc6,0x01,0x20,0x1d,0x22,0x07,0x7c, - 0xde,0xda,0xdc,0xd2,0xe0,0xde,0xe8,0xca,0xdc,0xe8,0x40,0xc6,0xd0,0xc2,0xe4,0xf8, - 0x4c,0xa5,0xb5,0xc1,0xb1,0x95,0x81,0x0c,0xad,0xac,0x80,0x50,0x09,0x05,0x05,0x0d, - 0x11,0x90,0x3a,0x18,0x62,0x20,0x74,0x80,0xd8,0xc1,0x72,0x0c,0x31,0x90,0x3b,0x40, - 0xee,0x60,0x39,0x46,0x44,0xec,0xc0,0x0e,0xf6,0xd0,0x0e,0x6e,0xd0,0x0e,0xef,0x40, - 0x0e,0xf5,0xc0,0x0e,0xe5,0xe0,0x06,0xe6,0xc0,0x0e,0xe1,0x70,0x0e,0xf3,0x30,0x45, - 0x08,0x86,0x11,0x0a,0x3b,0xb0,0x83,0x3d,0xb4,0x83,0x1b,0xa4,0x03,0x39,0x94,0x83, - 0x3b,0xd0,0xc3,0x94,0xa0,0x18,0xb1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39, - 0xc8,0xc3,0x3c,0xa4,0xc3,0x3b,0xb8,0xc3,0x94,0xc0,0x18,0x41,0x85,0x43,0x3a,0xc8, - 0x83,0x1b,0xb0,0x43,0x38,0xb8,0xc3,0x39,0xd4,0x43,0x38,0x9c,0x43,0x39,0xfc,0x82, - 0x3d,0x94,0x83,0x3c,0xcc,0x43,0x3a,0xbc,0x83,0x3b,0x4c,0x09,0x90,0x11,0x53,0x38, - 0xa4,0x83,0x3c,0xb8,0xc1,0x38,0xbc,0x43,0x3b,0xc0,0x43,0x3a,0xb0,0x43,0x39,0xfc, - 0xc2,0x3b,0xc0,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x3c,0x4c,0x19,0x14,0xc6,0x19, - 0xa1,0x84,0x43,0x3a,0xc8,0x83,0x1b,0xd8,0x43,0x39,0xc8,0x03,0x3d,0x94,0x03,0x3e, - 0x4c,0x09,0xe6,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c, - 0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07, - 0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e, - 0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43, - 0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c, - 0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76, - 0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e, - 0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8, - 0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4, - 0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68, - 0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07, - 0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71, - 0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5, - 0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4, - 0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90, - 0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43, - 0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b, - 0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78, - 0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2, - 0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20, - 0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0, - 0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83, - 0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07, - 0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61, - 0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d, - 0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39, - 0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79, - 0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3, - 0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4, - 0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8, - 0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83, - 0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00, - 0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x23,0x00,0x00,0x00, - 0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0xd4,0x63,0x11,0x40, - 0x60,0x1c,0x73,0x10,0x42,0xf0,0x3c,0x94,0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82, - 0xf0,0x2f,0x80,0x20,0x08,0xc2,0xbf,0x30,0x96,0x00,0x82,0x20,0x08,0x82,0x01,0x08, - 0x82,0x20,0x08,0x0e,0x33,0x00,0x24,0x73,0x10,0xd7,0x65,0x55,0x34,0x33,0x00,0x04, - 0x63,0x04,0x20,0x08,0x82,0xf8,0x37,0x46,0x00,0x82,0x20,0x08,0x7f,0x33,0x00,0x00, - 0xe3,0x0d,0x4c,0x64,0x51,0x40,0x2c,0x0a,0xe8,0x63,0xc1,0x02,0x1f,0x0b,0x16,0xf9, - 0x0c,0x32,0x04,0xcb,0x33,0xc8,0x10,0x2c,0xd1,0x6c,0xc3,0x52,0x01,0xb3,0x0d,0x41, - 0x15,0xcc,0x36,0x04,0x83,0x90,0x41,0x40,0x0c,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x5b,0x86,0x20,0xc0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _simgui_fs_bytecode_metal_ios[2809] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf9,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x20,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xf0,0xa4,0xb3,0x95,0x4b,0xab,0x64, - 0x94,0xe7,0xa9,0x8a,0x69,0x27,0x6d,0x28,0x77,0x84,0x8d,0x3f,0xaf,0x7d,0x3c,0x39, - 0x31,0xc4,0xcb,0x53,0x6d,0xc0,0x0d,0xdf,0x08,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0x04,0x0a,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0x7e,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5,0x06,0xa3,0x08,0x80, - 0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00,0x00,0x03,0x00,0x00, - 0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00,0x00,0x89,0x20,0x00, - 0x00,0x1d,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4, - 0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4, - 0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c,0x20,0x00,0x47,0x49, - 0x53,0x44,0x09,0x93,0xff,0x4f,0xc4,0x35,0x51,0x11,0xf1,0xdb,0xc3,0x3f,0x8d,0x11, - 0x00,0x83,0x08,0x44,0x70,0x91,0x34,0x45,0x94,0x30,0xf9,0xbf,0x04,0x30,0xcf,0x42, - 0x44,0xff,0x34,0x46,0x00,0x0c,0x22,0x18,0x42,0x29,0xc4,0x08,0xe5,0x10,0x9a,0x23, - 0x08,0xe6,0x08,0xc0,0x60,0x18,0x41,0x58,0x0a,0x12,0xca,0x19,0x8a,0x29,0x40,0x6d, - 0x20,0x20,0x05,0xd6,0x08,0x00,0x00,0x00,0x00,0x13,0xa8,0x70,0x48,0x07,0x79,0xb0, - 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x74,0x78,0x87, - 0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f, - 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9, - 0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0, - 0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07, - 0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0, - 0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, - 0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, - 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xf6,0x20, - 0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x40,0x07,0x78, - 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07,0x76,0xa0,0x07, - 0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x72, - 0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60, - 0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07, - 0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a, - 0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10, - 0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07,0x70,0x20,0x07, - 0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, - 0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20,0x07,0x43,0x98, - 0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03,0x04,0x80,0x00,0x00, - 0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98, - 0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02, - 0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0x01,0x12,0x00,0x00,0x79,0x18,0x00, - 0x00,0xb9,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32, - 0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b, - 0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc2,0x23,0x2c,0x05,0xe7,0x20,0x08, - 0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed, - 0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c, - 0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45, - 0x26,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46,0x17, - 0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6, - 0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96, - 0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f, - 0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c, - 0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99, - 0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d, - 0x11,0x9e,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d, - 0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c, - 0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2, - 0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d, - 0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0x9e,0x67,0x19,0x1e,0xe8,0x89,0x1e,0xe9, - 0x99,0x86,0x08,0x0f,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc, - 0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb, - 0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e, - 0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34, - 0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28,0xd4,0xd9,0x0d,0x91,0x96,0xe1,0xb1,0x9e,0xeb, - 0xc1,0x9e,0xec,0x81,0x1e,0xed,0x91,0x9e,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb, - 0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1,0x37,0xb6,0x37,0xb9,0x21,0xd2,0x22,0x3c,0xd6, - 0xd3,0x3d,0xd8,0x93,0x3d,0xd0,0x13,0x3d,0xd2,0xe3,0x71,0x09,0x4b,0x93,0x73,0xa1, - 0x2b,0xc3,0xa3,0xab,0x93,0x2b,0xa3,0x14,0x96,0x26,0xe7,0xc2,0xf6,0x36,0x16,0x46, - 0x97,0xf6,0xe6,0xf6,0x95,0xe6,0x46,0x56,0x86,0x47,0x25,0x2c,0x4d,0xce,0x65,0x2e, - 0xac,0x0d,0x8e,0xad,0x8c,0x18,0x5d,0x19,0x1e,0x5d,0x9d,0x5c,0x99,0x0c,0x19,0x8f, - 0x19,0xdb,0x5b,0x18,0x1d,0x0b,0xc8,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x0f,0x07,0xba, - 0x32,0xbc,0x21,0xd4,0x42,0x3c,0x60,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x23,0x06,0x0f, - 0xf4,0x8c,0xc1,0x23,0x3d,0x64,0xc0,0x25,0x2c,0x4d,0xce,0x65,0x2e,0xac,0x0d,0x8e, - 0xad,0x4c,0x8e,0xc7,0x5c,0x58,0x1b,0x1c,0x5b,0x99,0x1c,0x87,0xb9,0x36,0xb8,0x21, - 0xd2,0x72,0x3c,0x66,0xf0,0x84,0xc1,0x32,0x2c,0xc2,0x03,0x3d,0x67,0xf0,0x48,0x0f, - 0x1a,0x0c,0x41,0x1e,0xee,0xf9,0x9e,0x32,0x78,0xd2,0x60,0x88,0x91,0x00,0x4f,0xf5, - 0xa8,0xc1,0x88,0x88,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xda,0xe1,0x1d,0xc8,0xa1, - 0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c,0xd8,0x21,0x1c,0xce,0x61,0x1e,0xa6,0x08,0xc1, - 0x30,0x42,0x61,0x07,0x76,0xb0,0x87,0x76,0x70,0x83,0x74,0x20,0x87,0x72,0x70,0x07, - 0x7a,0x98,0x12,0x14,0x23,0x96,0x70,0x48,0x07,0x79,0x70,0x03,0x7b,0x28,0x07,0x79, - 0x98,0x87,0x74,0x78,0x07,0x77,0x98,0x12,0x18,0x23,0xa8,0x70,0x48,0x07,0x79,0x70, - 0x03,0x76,0x08,0x07,0x77,0x38,0x87,0x7a,0x08,0x87,0x73,0x28,0x87,0x5f,0xb0,0x87, - 0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x01,0x32,0x62,0x0a,0x87,0x74, - 0x90,0x07,0x37,0x18,0x87,0x77,0x68,0x07,0x78,0x48,0x07,0x76,0x28,0x87,0x5f,0x78, - 0x07,0x78,0xa0,0x87,0x74,0x78,0x07,0x77,0x98,0x87,0x29,0x83,0xc2,0x38,0x23,0x98, - 0x70,0x48,0x07,0x79,0x70,0x03,0x73,0x90,0x87,0x70,0x38,0x87,0x76,0x28,0x07,0x77, - 0xa0,0x87,0x29,0xc1,0x1a,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00, - 0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84, - 0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed, - 0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66, - 0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c, - 0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70, - 0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90, - 0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4, - 0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83, - 0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14, - 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70, - 0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80, - 0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0, - 0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1, - 0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d, - 0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39, - 0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc, - 0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70, - 0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53, - 0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e, - 0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c, - 0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38, - 0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37, - 0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33, - 0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4, - 0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0, - 0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3, - 0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07, - 0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23, - 0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59, - 0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b, - 0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00, - 0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f, - 0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20, - 0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x0c,0x00,0x00,0x00,0x13,0x04,0x41, - 0x2c,0x10,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xc4,0x46,0x00,0x48,0x8d,0x00,0xd4, - 0x00,0x89,0x19,0x00,0x02,0x23,0x00,0x00,0x00,0x23,0x06,0x8a,0x10,0x44,0x87,0x91, - 0x0c,0x05,0x11,0x58,0x90,0xc8,0x67,0xb6,0x81,0x08,0x80,0x0c,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _simgui_vs_source_metal_sim[672] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x32,0x20,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x3b, - 0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e, - 0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, - 0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63, - 0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c, - 0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20, - 0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, - 0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62, - 0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x5b, - 0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x32, - 0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74,0x65,0x78,0x20, - 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28, - 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74, - 0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61, - 0x6e,0x74,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x26,0x20,0x5f,0x32, - 0x32,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29, - 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74, - 0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f, - 0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x28,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73, - 0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x5f,0x32,0x32,0x2e,0x64,0x69,0x73,0x70, - 0x5f,0x73,0x69,0x7a,0x65,0x29,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28, - 0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x32, - 0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e,0x35,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75,0x76, - 0x20,0x3d,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, - 0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, - -}; -static const uint8_t _simgui_fs_source_metal_sim[436] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, - 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, - 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, - 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20, - 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, - 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, - 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65, - 0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, - 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, - 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65, - 0x78,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d, - 0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b, - 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75, - 0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, - 0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e, - 0x75,0x76,0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _simgui_vs_bytecode_hlsl4[892] = { - 0x44,0x58,0x42,0x43,0x0d,0xbd,0x9e,0x9e,0x7d,0xc0,0x2b,0x54,0x88,0xf9,0xca,0x89, - 0x32,0xe4,0x0c,0x59,0x01,0x00,0x00,0x00,0x7c,0x03,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x60,0x01,0x00,0x00,0xd0,0x01,0x00,0x00, - 0x00,0x03,0x00,0x00,0x52,0x44,0x45,0x46,0xc0,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0x98,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00, - 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x88,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x32,0x32,0x5f,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a, - 0x65,0x00,0xab,0xab,0x01,0x00,0x03,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52, - 0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e, - 0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab, - 0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, - 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x0c,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab, - 0x53,0x48,0x44,0x52,0x28,0x01,0x00,0x00,0x40,0x00,0x01,0x00,0x4a,0x00,0x00,0x00, - 0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, - 0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00, - 0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04, - 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02, - 0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0xf2,0x20,0x10,0x00, - 0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00,0x0e,0x00,0x00,0x08, - 0x32,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x80,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a, - 0x32,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x02,0x40,0x00,0x00,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x0a,0x32,0x20,0x10,0x00,0x02,0x00,0x00,0x00, - 0x46,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x40, - 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x08, - 0xc2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x80,0x3f,0x3e,0x00,0x00,0x01, - 0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _simgui_fs_bytecode_hlsl4[608] = { - 0x44,0x58,0x42,0x43,0x3a,0xa7,0x41,0x21,0xb4,0x2d,0xa7,0x6e,0xfe,0x31,0xb0,0xe0, - 0x14,0xe0,0xdf,0x5a,0x01,0x00,0x00,0x00,0x60,0x02,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x14,0x01,0x00,0x00,0x48,0x01,0x00,0x00, - 0xe4,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0x64,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c, - 0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c, - 0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00, - 0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, - 0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54, - 0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0x94,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00, - 0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00, - 0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00, - 0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00, - 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00, - 0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - -}; -#elif defined(SOKOL_WGPU) -static const uint8_t _simgui_vs_source_wgsl[1083] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28, - 0x30,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20,0x76, - 0x61,0x72,0x3c,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x32,0x32, - 0x20,0x3a,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x76, - 0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a, - 0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72, - 0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f, - 0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x31,0x39, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x5f,0x31,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x35,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x78,0x5f,0x32,0x32, - 0x2e,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x33,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d, - 0x20,0x28,0x28,0x28,0x78,0x5f,0x31,0x39,0x20,0x2f,0x20,0x78,0x5f,0x32,0x35,0x29, - 0x20,0x2d,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x30,0x2e,0x35,0x66,0x2c,0x20,0x30, - 0x2e,0x35,0x66,0x29,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x32,0x66,0x28,0x32,0x2e, - 0x30,0x66,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x66,0x29,0x29,0x3b,0x0a,0x20,0x20,0x67, - 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63, - 0x34,0x66,0x28,0x78,0x5f,0x33,0x33,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x33,0x33,0x2e, - 0x79,0x2c,0x20,0x30,0x2e,0x35,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x3b,0x0a, - 0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x33,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x78,0x5f,0x34,0x33,0x3b,0x0a,0x20,0x20,0x6c, - 0x65,0x74,0x20,0x78,0x5f,0x34,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3d,0x20,0x78,0x5f,0x34,0x37,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75, - 0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61, - 0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c, - 0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x28,0x30,0x29,0x0a,0x20,0x20,0x75,0x76,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x31,0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78, - 0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x28,0x30,0x29,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x32,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e, - 0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65, - 0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _simgui_fs_source_wgsl[630] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x34,0x38, - 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, - 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x36,0x34,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a, - 0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x78,0x5f,0x32,0x33,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x32,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x34,0x20,0x2a,0x20,0x78,0x5f, - 0x32,0x37,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d, - 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75, - 0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x30,0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x5f, - 0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x66, - 0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29, - 0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20, - 0x20,0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28, - 0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e, - 0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29, - 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _simgui_vs_source_dummy = ""; -static const char* _simgui_fs_source_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) -static void _simgui_set_clipboard(ImGuiContext* ctx, const char* text) { - (void)ctx; - sapp_set_clipboard_string(text); -} - -static const char* _simgui_get_clipboard(ImGuiContext* ctx) { - (void)ctx; - return sapp_get_clipboard_string(); -} -#endif - -#if defined(__EMSCRIPTEN__) && !defined(SOKOL_DUMMY_BACKEND) -EM_JS(int, simgui_js_is_osx, (void), { - if (navigator.userAgent.includes('Macintosh')) { - return 1; - } else { - return 0; - } -}); -#endif - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SIMGUI_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _simgui_log_messages[] = { - _SIMGUI_LOG_ITEMS -}; -#undef _SIMGUI_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SIMGUI_PANIC(code) _simgui_log(SIMGUI_LOGITEM_ ##code, 0, 0, __LINE__) -#define _SIMGUI_ERROR(code) _simgui_log(SIMGUI_LOGITEM_ ##code, 1, 0, __LINE__) -#define _SIMGUI_WARN(code) _simgui_log(SIMGUI_LOGITEM_ ##code, 2, 0, __LINE__) -#define _SIMGUI_INFO(code) _simgui_log(SIMGUI_LOGITEM_ ##code, 3, 0, __LINE__) -#define _SIMGUI_LOGMSG(code,msg) _simgui_log(SIMGUI_LOGITEM_ ##code, 3, msg, __LINE__) - -static void _simgui_log(simgui_log_item_t log_item, uint32_t log_level, const char* msg, uint32_t line_nr) { - if (_simgui.desc.logger.func) { - const char* filename = 0; - #if defined(SOKOL_DEBUG) - filename = __FILE__; - if (0 == msg) { - msg = _simgui_log_messages[log_item]; - } - #endif - _simgui.desc.logger.func("simgui", log_level, log_item, msg, line_nr, filename, _simgui.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -static void _simgui_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -static void* _simgui_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_simgui.desc.allocator.alloc_fn) { - ptr = _simgui.desc.allocator.alloc_fn(size, _simgui.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SIMGUI_PANIC(MALLOC_FAILED); - } - return ptr; -} - -static void* _simgui_malloc_clear(size_t size) { - void* ptr = _simgui_malloc(size); - _simgui_clear(ptr, size); - return ptr; -} - -static void _simgui_free(void* ptr) { - if (_simgui.desc.allocator.free_fn) { - _simgui.desc.allocator.free_fn(ptr, _simgui.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ██████ ██████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ -// -// >>pool -static void _simgui_init_pool(_simgui_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - // slot 0 is reserved for the 'invalid id', so bump the pool size by 1 - pool->size = num + 1; - pool->queue_top = 0; - // generation counters indexable by pool slot index, slot 0 is reserved - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*) _simgui_malloc_clear(gen_ctrs_size); - // it's not a bug to only reserve 'num' here - pool->free_queue = (int*) _simgui_malloc_clear(sizeof(int) * (size_t)num); - // never allocate the zero-th pool item since the invalid id is 0 - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -static void _simgui_discard_pool(_simgui_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _simgui_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _simgui_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -static int _simgui_pool_alloc_index(_simgui_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SIMGUI_INVALID_SLOT_INDEX; - } -} - -static void _simgui_pool_free_index(_simgui_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SIMGUI_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - // debug check against double-free - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -/* initialize a pool slot: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the handle id -*/ -static uint32_t _simgui_slot_init(_simgui_pool_t* pool, _simgui_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SIMGUI_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT((slot->state == _SIMGUI_RESOURCESTATE_INITIAL) && (slot->id == SIMGUI_INVALID_ID)); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SIMGUI_SLOT_SHIFT)|(slot_index & _SIMGUI_SLOT_MASK); - slot->state = _SIMGUI_RESOURCESTATE_ALLOC; - return slot->id; -} - -// extract slot index from id -static int _simgui_slot_index(uint32_t id) { - int slot_index = (int) (id & _SIMGUI_SLOT_MASK); - SOKOL_ASSERT(_SIMGUI_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -static void _simgui_init_item_pool(_simgui_pool_t* pool, int pool_size, void** items_ptr, size_t item_size_bytes) { - // NOTE: the pools will have an additional item, since slot 0 is reserved - SOKOL_ASSERT(pool && (pool->size == 0)); - SOKOL_ASSERT((pool_size > 0) && (pool_size < _SIMGUI_MAX_POOL_SIZE)); - SOKOL_ASSERT(items_ptr && (*items_ptr == 0)); - SOKOL_ASSERT(item_size_bytes > 0); - _simgui_init_pool(pool, pool_size); - const size_t pool_size_bytes = item_size_bytes * (size_t)pool->size; - *items_ptr = _simgui_malloc_clear(pool_size_bytes); -} - -static void _simgui_discard_item_pool(_simgui_pool_t* pool, void** items_ptr) { - SOKOL_ASSERT(pool && (pool->size != 0)); - SOKOL_ASSERT(items_ptr && (*items_ptr != 0)); - _simgui_free(*items_ptr); *items_ptr = 0; - _simgui_discard_pool(pool); -} - -static void _simgui_setup_image_pool(int pool_size) { - _simgui_image_pool_t* p = &_simgui.image_pool; - _simgui_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_simgui_image_t)); -} - -static void _simgui_discard_image_pool(void) { - _simgui_image_pool_t* p = &_simgui.image_pool; - _simgui_discard_item_pool(&p->pool, (void**)&p->items); -} - -static simgui_image_t _simgui_make_image_handle(uint32_t id) { - simgui_image_t handle = { id }; - return handle; -} - -static _simgui_image_t* _simgui_image_at(uint32_t id) { - SOKOL_ASSERT(SIMGUI_INVALID_ID != id); - const _simgui_image_pool_t* p = &_simgui.image_pool; - int slot_index = _simgui_slot_index(id); - SOKOL_ASSERT((slot_index > _SIMGUI_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _simgui_image_t* _simgui_lookup_image(uint32_t id) { - if (SIMGUI_INVALID_ID != id) { - _simgui_image_t* img = _simgui_image_at(id); - if (img->slot.id == id) { - return img; - } - } - return 0; -} - -static simgui_image_t _simgui_alloc_image(void) { - _simgui_image_pool_t* p = &_simgui.image_pool; - int slot_index = _simgui_pool_alloc_index(&p->pool); - if (_SIMGUI_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _simgui_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _simgui_make_image_handle(id); - } else { - // pool exhausted - return _simgui_make_image_handle(SIMGUI_INVALID_ID); - } -} - -static _simgui_resource_state _simgui_init_image(_simgui_image_t* img, const simgui_image_desc_t* desc) { - SOKOL_ASSERT(img && (img->slot.state == _SIMGUI_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - SOKOL_ASSERT(_simgui.def_pip.id != SIMGUI_INVALID_ID); - SOKOL_ASSERT(_simgui.pip_unfilterable.id != SIMGUI_INVALID_ID); - img->image = desc->image; - img->sampler = desc->sampler; - if (sg_query_pixelformat(sg_query_image_desc(desc->image).pixel_format).filter) { - img->pip = _simgui.def_pip; - } else { - img->pip = _simgui.pip_unfilterable; - } - return _SIMGUI_RESOURCESTATE_VALID; -} - -static void _simgui_deinit_image(_simgui_image_t* img) { - SOKOL_ASSERT(img); - img->image.id = SIMGUI_INVALID_ID; - img->sampler.id = SIMGUI_INVALID_ID; - img->pip.id = SIMGUI_INVALID_ID; -} - -static void _simgui_destroy_image(simgui_image_t img_id) { - _simgui_image_t* img = _simgui_lookup_image(img_id.id); - if (img) { - _simgui_deinit_image(img); - _simgui_image_pool_t* p = &_simgui.image_pool; - _simgui_clear(img, sizeof(_simgui_image_t)); - _simgui_pool_free_index(&p->pool, _simgui_slot_index(img_id.id)); - } -} - -static void _simgui_destroy_all_images(void) { - _simgui_image_pool_t* p = &_simgui.image_pool; - for (int i = 0; i < p->pool.size; i++) { - _simgui_image_t* img = &p->items[i]; - _simgui_destroy_image(_simgui_make_image_handle(img->slot.id)); - } -} - -static simgui_image_desc_t _simgui_image_desc_defaults(const simgui_image_desc_t* desc) { - SOKOL_ASSERT(desc); - simgui_image_desc_t res = *desc; - res.image.id = _simgui_def(res.image.id, _simgui.def_img.id); - res.sampler.id = _simgui_def(res.sampler.id, _simgui.def_smp.id); - return res; -} - -static bool _simgui_is_osx(void) { - #if defined(SOKOL_DUMMY_BACKEND) - return false; - #elif defined(__EMSCRIPTEN__) - return simgui_js_is_osx(); - #elif defined(__APPLE__) - return true; - #else - return false; - #endif -} - -static simgui_desc_t _simgui_desc_defaults(const simgui_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - simgui_desc_t res = *desc; - res.max_vertices = _simgui_def(res.max_vertices, 65536); - res.image_pool_size = _simgui_def(res.image_pool_size, 256); - return res; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) { - SOKOL_ASSERT(desc); - _simgui_clear(&_simgui, sizeof(_simgui)); - _simgui.init_cookie = _SIMGUI_INIT_COOKIE; - _simgui.desc = _simgui_desc_defaults(desc); - _simgui.cur_dpi_scale = 1.0f; - #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) - _simgui.is_osx = _simgui_is_osx(); - #endif - // can keep color_format, depth_format and sample_count as is, - // since sokol_gfx.h will do its own default-value handling - - // setup image pool - _simgui_setup_image_pool(_simgui.desc.image_pool_size); - - // allocate an intermediate vertex- and index-buffer - SOKOL_ASSERT(_simgui.desc.max_vertices > 0); - _simgui.vertices.size = (size_t)_simgui.desc.max_vertices * sizeof(ImDrawVert); - _simgui.vertices.ptr = _simgui_malloc(_simgui.vertices.size); - _simgui.indices.size = (size_t)_simgui.desc.max_vertices * 3 * sizeof(ImDrawIdx); - _simgui.indices.ptr = _simgui_malloc(_simgui.indices.size); - - // initialize Dear ImGui - #if defined(__cplusplus) - ImGui::CreateContext(); - ImGui::StyleColorsDark(); - ImGuiIO* io = &ImGui::GetIO(); - ImGuiPlatformIO* pio = &ImGui::GetPlatformIO(); - if (!_simgui.desc.no_default_font) { - io->Fonts->AddFontDefault(); - } - #else - igCreateContext(NULL); - igStyleColorsDark(igGetStyle()); - ImGuiIO* io = igGetIO(); - ImGuiPlatformIO* pio = igGetPlatformIO(); - if (!_simgui.desc.no_default_font) { - ImFontAtlas_AddFontDefault(io->Fonts, NULL); - } - #endif - io->IniFilename = _simgui.desc.ini_filename; - io->ConfigMacOSXBehaviors = _simgui_is_osx(); - io->BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; - #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) - if (!_simgui.desc.disable_set_mouse_cursor) { - io->BackendFlags |= ImGuiBackendFlags_HasMouseCursors; - } - pio->Platform_SetClipboardTextFn = _simgui_set_clipboard; - pio->Platform_GetClipboardTextFn = _simgui_get_clipboard; - #endif - io->ConfigWindowsResizeFromEdges = !_simgui.desc.disable_windows_resize_from_edges; - - // create sokol-gfx resources - sg_push_debug_group("sokol-imgui"); - - // shader object for using the embedded shader source (or bytecode) - sg_shader_desc shd_desc; - _simgui_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - sg_shader_uniform_block_desc* ub = &shd_desc.vs.uniform_blocks[0]; - ub->size = sizeof(_simgui_vs_params_t); - ub->uniforms[0].name = "vs_params"; - ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - ub->uniforms[0].array_count = 1; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - shd_desc.label = "sokol-imgui-shader"; - #if defined(SOKOL_GLCORE) - shd_desc.vs.source = (const char*)_simgui_vs_source_glsl410; - shd_desc.fs.source = (const char*)_simgui_fs_source_glsl410; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = (const char*)_simgui_vs_source_glsl300es; - shd_desc.fs.source = (const char*)_simgui_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = (const char*)_simgui_vs_source_metal_sim; - shd_desc.fs.source = (const char*)_simgui_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = (const char*)_simgui_vs_source_wgsl; - shd_desc.fs.source = (const char*)_simgui_fs_source_wgsl; - #else - shd_desc.vs.source = _simgui_vs_source_dummy; - shd_desc.fs.source = _simgui_fs_source_dummy; - #endif - _simgui.def_shd = sg_make_shader(&shd_desc); - - // pipeline object for imgui rendering - sg_pipeline_desc pip_desc; - _simgui_clear(&pip_desc, sizeof(pip_desc)); - pip_desc.layout.buffers[0].stride = sizeof(ImDrawVert); - { - sg_vertex_attr_state* attr = &pip_desc.layout.attrs[0]; - attr->offset = offsetof(ImDrawVert, pos); - attr->format = SG_VERTEXFORMAT_FLOAT2; - } - { - sg_vertex_attr_state* attr = &pip_desc.layout.attrs[1]; - attr->offset = offsetof(ImDrawVert, uv); - attr->format = SG_VERTEXFORMAT_FLOAT2; - } - { - sg_vertex_attr_state* attr = &pip_desc.layout.attrs[2]; - attr->offset = offsetof(ImDrawVert, col); - attr->format = SG_VERTEXFORMAT_UBYTE4N; - } - pip_desc.shader = _simgui.def_shd; - pip_desc.index_type = SG_INDEXTYPE_UINT16; - pip_desc.sample_count = _simgui.desc.sample_count; - pip_desc.depth.pixel_format = _simgui.desc.depth_format; - pip_desc.colors[0].pixel_format = _simgui.desc.color_format; - pip_desc.colors[0].write_mask = _simgui.desc.write_alpha_channel ? SG_COLORMASK_RGBA : SG_COLORMASK_RGB; - pip_desc.colors[0].blend.enabled = true; - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - if (_simgui.desc.write_alpha_channel) { - pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ONE; - pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE; - } - pip_desc.label = "sokol-imgui-pipeline"; - _simgui.def_pip = sg_make_pipeline(&pip_desc); - - // create a unfilterable/nonfiltering variants of the shader and pipeline - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_NONFILTERING; - shd_desc.label = "sokol-imgui-shader-unfilterable"; - _simgui.shd_unfilterable = sg_make_shader(&shd_desc); - pip_desc.shader = _simgui.shd_unfilterable; - pip_desc.label = "sokol-imgui-pipeline-unfilterable"; - _simgui.pip_unfilterable = sg_make_pipeline(&pip_desc); - - // NOTE: since we're in C++ mode here we can't use C99 designated init - sg_buffer_desc vb_desc; - _simgui_clear(&vb_desc, sizeof(vb_desc)); - vb_desc.usage = SG_USAGE_STREAM; - vb_desc.size = _simgui.vertices.size; - vb_desc.label = "sokol-imgui-vertices"; - _simgui.vbuf = sg_make_buffer(&vb_desc); - - sg_buffer_desc ib_desc; - _simgui_clear(&ib_desc, sizeof(ib_desc)); - ib_desc.type = SG_BUFFERTYPE_INDEXBUFFER; - ib_desc.usage = SG_USAGE_STREAM; - ib_desc.size = _simgui.indices.size; - ib_desc.label = "sokol-imgui-indices"; - _simgui.ibuf = sg_make_buffer(&ib_desc); - - // a default user-image sampler - sg_sampler_desc def_sampler_desc; - _simgui_clear(&def_sampler_desc, sizeof(def_sampler_desc)); - def_sampler_desc.min_filter = SG_FILTER_NEAREST; - def_sampler_desc.mag_filter = SG_FILTER_NEAREST; - def_sampler_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; - def_sampler_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; - def_sampler_desc.label = "sokol-imgui-default-sampler"; - _simgui.def_smp = sg_make_sampler(&def_sampler_desc); - - // a default user image - static uint32_t def_pixels[64]; - memset(def_pixels, 0xFF, sizeof(def_pixels)); - sg_image_desc def_image_desc; - _simgui_clear(&def_image_desc, sizeof(def_image_desc)); - def_image_desc.width = 8; - def_image_desc.height = 8; - def_image_desc.pixel_format = SG_PIXELFORMAT_RGBA8; - def_image_desc.data.subimage[0][0].ptr = def_pixels; - def_image_desc.data.subimage[0][0].size = sizeof(def_pixels); - def_image_desc.label = "sokol-imgui-default-image"; - _simgui.def_img = sg_make_image(&def_image_desc); - - // default font texture - if (!_simgui.desc.no_default_font) { - simgui_font_tex_desc_t simgui_font_smp_desc; - _simgui_clear(&simgui_font_smp_desc, sizeof(simgui_font_smp_desc)); - simgui_create_fonts_texture(&simgui_font_smp_desc); - } - - sg_pop_debug_group(); -} - -SOKOL_API_IMPL void simgui_create_fonts_texture(const simgui_font_tex_desc_t* desc) { - SOKOL_ASSERT(desc); - SOKOL_ASSERT(SG_INVALID_ID == _simgui.font_smp.id); - SOKOL_ASSERT(SG_INVALID_ID == _simgui.font_img.id); - SOKOL_ASSERT(SIMGUI_INVALID_ID == _simgui.default_font.id); - - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #else - ImGuiIO* io = igGetIO(); - #endif - - // a default font sampler - sg_sampler_desc font_smp_desc; - _simgui_clear(&font_smp_desc, sizeof(font_smp_desc)); - font_smp_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; - font_smp_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; - font_smp_desc.min_filter = desc->min_filter; - font_smp_desc.mag_filter = desc->mag_filter; - font_smp_desc.label = "sokol-imgui-font-sampler"; - _simgui.font_smp = sg_make_sampler(&font_smp_desc); - - unsigned char* font_pixels; - int font_width, font_height; - #if defined(__cplusplus) - io->Fonts->GetTexDataAsRGBA32(&font_pixels, &font_width, &font_height); - #else - int bytes_per_pixel; - ImFontAtlas_GetTexDataAsRGBA32(io->Fonts, &font_pixels, &font_width, &font_height, &bytes_per_pixel); - #endif - sg_image_desc font_img_desc; - _simgui_clear(&font_img_desc, sizeof(font_img_desc)); - font_img_desc.width = font_width; - font_img_desc.height = font_height; - font_img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; - font_img_desc.data.subimage[0][0].ptr = font_pixels; - font_img_desc.data.subimage[0][0].size = (size_t)(font_width * font_height) * sizeof(uint32_t); - font_img_desc.label = "sokol-imgui-font-image"; - _simgui.font_img = sg_make_image(&font_img_desc); - - simgui_image_desc_t img_desc; - _simgui_clear(&img_desc, sizeof(img_desc)); - img_desc.image = _simgui.font_img; - img_desc.sampler = _simgui.font_smp; - _simgui.default_font = simgui_make_image(&img_desc); - io->Fonts->TexID = simgui_imtextureid(_simgui.default_font); -} - -SOKOL_API_IMPL void simgui_destroy_fonts_texture(void) { - // NOTE: it's valid to call the destroy funcs with SG_INVALID_ID - sg_destroy_sampler(_simgui.font_smp); - sg_destroy_image(_simgui.font_img); - simgui_destroy_image(_simgui.default_font); - _simgui.font_smp.id = SG_INVALID_ID; - _simgui.font_img.id = SG_INVALID_ID; - _simgui.default_font.id = SIMGUI_INVALID_ID; -} - -SOKOL_API_IMPL void simgui_shutdown(void) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGui::DestroyContext(); - #else - igDestroyContext(0); - #endif - // NOTE: it's valid to call the destroy funcs with SG_INVALID_ID - sg_destroy_pipeline(_simgui.pip_unfilterable); - sg_destroy_shader(_simgui.shd_unfilterable); - sg_destroy_pipeline(_simgui.def_pip); - sg_destroy_shader(_simgui.def_shd); - sg_destroy_sampler(_simgui.font_smp); - sg_destroy_image(_simgui.font_img); - sg_destroy_sampler(_simgui.def_smp); - sg_destroy_image(_simgui.def_img); - sg_destroy_buffer(_simgui.ibuf); - sg_destroy_buffer(_simgui.vbuf); - sg_pop_debug_group(); - sg_push_debug_group("sokol-imgui"); - _simgui_destroy_all_images(); - _simgui_discard_image_pool(); - SOKOL_ASSERT(_simgui.vertices.ptr); - _simgui_free((void*)_simgui.vertices.ptr); - SOKOL_ASSERT(_simgui.indices.ptr); - _simgui_free((void*)_simgui.indices.ptr); - _simgui.init_cookie = 0; -} - -SOKOL_API_IMPL simgui_image_t simgui_make_image(const simgui_image_desc_t* desc) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - SOKOL_ASSERT(desc); - const simgui_image_desc_t desc_def = _simgui_image_desc_defaults(desc); - simgui_image_t img_id = _simgui_alloc_image(); - _simgui_image_t* img = _simgui_lookup_image(img_id.id); - if (img) { - img->slot.state = _simgui_init_image(img, &desc_def); - SOKOL_ASSERT((img->slot.state == _SIMGUI_RESOURCESTATE_VALID) || (img->slot.state == _SIMGUI_RESOURCESTATE_FAILED)); - } else { - _SIMGUI_ERROR(IMAGE_POOL_EXHAUSTED); - } - return img_id; -} - -SOKOL_API_IMPL void simgui_destroy_image(simgui_image_t img_id) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - _simgui_destroy_image(img_id); -} - -SOKOL_API_IMPL simgui_image_desc_t simgui_query_image_desc(simgui_image_t img_id) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - _simgui_image_t* img = _simgui_lookup_image(img_id.id); - simgui_image_desc_t desc; - _simgui_clear(&desc, sizeof(desc)); - if (img) { - desc.image = img->image; - desc.sampler = img->sampler; - } - return desc; -} - -SOKOL_API_IMPL void* simgui_imtextureid(simgui_image_t img) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - return (void*)(uintptr_t)img.id; -} - -SOKOL_API_IMPL simgui_image_t simgui_image_from_imtextureid(void* im_texture_id) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - simgui_image_t img = { (uint32_t)(uintptr_t) im_texture_id }; - return img; -} - -SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - SOKOL_ASSERT(desc); - SOKOL_ASSERT(desc->width > 0); - SOKOL_ASSERT(desc->height > 0); - _simgui.cur_dpi_scale = _simgui_def(desc->dpi_scale, 1.0f); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #else - ImGuiIO* io = igGetIO(); - #endif - if (!io->Fonts->TexReady) { - simgui_destroy_fonts_texture(); - simgui_font_tex_desc_t simgui_font_smp_desc; - _simgui_clear(&simgui_font_smp_desc, sizeof(simgui_font_smp_desc)); - simgui_create_fonts_texture(&simgui_font_smp_desc); - } - io->DisplaySize.x = ((float)desc->width) / _simgui.cur_dpi_scale; - io->DisplaySize.y = ((float)desc->height) / _simgui.cur_dpi_scale; - io->DeltaTime = (float)desc->delta_time; - #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) - if (io->WantTextInput && !sapp_keyboard_shown()) { - sapp_show_keyboard(true); - } - if (!io->WantTextInput && sapp_keyboard_shown()) { - sapp_show_keyboard(false); - } - if (!_simgui.desc.disable_set_mouse_cursor) { - #if defined(__cplusplus) - ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); - #else - ImGuiMouseCursor imgui_cursor = igGetMouseCursor(); - #endif - sapp_mouse_cursor cursor = sapp_get_mouse_cursor(); - switch (imgui_cursor) { - case ImGuiMouseCursor_Arrow: cursor = SAPP_MOUSECURSOR_ARROW; break; - case ImGuiMouseCursor_TextInput: cursor = SAPP_MOUSECURSOR_IBEAM; break; - case ImGuiMouseCursor_ResizeAll: cursor = SAPP_MOUSECURSOR_RESIZE_ALL; break; - case ImGuiMouseCursor_ResizeNS: cursor = SAPP_MOUSECURSOR_RESIZE_NS; break; - case ImGuiMouseCursor_ResizeEW: cursor = SAPP_MOUSECURSOR_RESIZE_EW; break; - case ImGuiMouseCursor_ResizeNESW: cursor = SAPP_MOUSECURSOR_RESIZE_NESW; break; - case ImGuiMouseCursor_ResizeNWSE: cursor = SAPP_MOUSECURSOR_RESIZE_NWSE; break; - case ImGuiMouseCursor_Hand: cursor = SAPP_MOUSECURSOR_POINTING_HAND; break; - case ImGuiMouseCursor_NotAllowed: cursor = SAPP_MOUSECURSOR_NOT_ALLOWED; break; - default: break; - } - sapp_set_mouse_cursor(cursor); - } - #endif - #if defined(__cplusplus) - ImGui::NewFrame(); - #else - igNewFrame(); - #endif -} - -static const _simgui_image_t* _simgui_bind_image_sampler(sg_bindings* bindings, ImTextureID tex_id) { - const _simgui_image_t* img = _simgui_lookup_image((uint32_t)(uintptr_t)tex_id); - if (img) { - bindings->fs.images[0] = img->image; - bindings->fs.samplers[0] = img->sampler; - } else { - bindings->fs.images[0] = _simgui.def_img; - bindings->fs.samplers[0] = _simgui.def_smp; - } - return img; -} - -static ImDrawList* _simgui_imdrawlist_at(ImDrawData* draw_data, int cl_index) { - #if defined(__cplusplus) - return draw_data->CmdLists[cl_index]; - #else - return draw_data->CmdLists.Data[cl_index]; - #endif -} - -SOKOL_API_IMPL void simgui_render(void) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGui::Render(); - ImDrawData* draw_data = ImGui::GetDrawData(); - ImGuiIO* io = &ImGui::GetIO(); - #else - igRender(); - ImDrawData* draw_data = igGetDrawData(); - ImGuiIO* io = igGetIO(); - #endif - if (0 == draw_data) { - return; - } - if (draw_data->CmdListsCount == 0) { - return; - } - /* copy vertices and indices into an intermediate buffer so that - they can be updated with a single sg_update_buffer() call each - (sg_append_buffer() has performance problems on some GL platforms), - also keep track of valid number of command lists in case of a - buffer overflow - */ - size_t all_vtx_size = 0; - size_t all_idx_size = 0; - int cmd_list_count = 0; - for (int cl_index = 0; cl_index < draw_data->CmdListsCount; cl_index++, cmd_list_count++) { - ImDrawList* cl = _simgui_imdrawlist_at(draw_data, cl_index); - const size_t vtx_size = (size_t)cl->VtxBuffer.Size * sizeof(ImDrawVert); - const size_t idx_size = (size_t)cl->IdxBuffer.Size * sizeof(ImDrawIdx); - - // check for buffer overflow - if (((all_vtx_size + vtx_size) > _simgui.vertices.size) || - ((all_idx_size + idx_size) > _simgui.indices.size)) - { - break; - } - - // copy vertices and indices into common buffers - if (vtx_size > 0) { - const ImDrawVert* src_vtx_ptr = cl->VtxBuffer.Data; - void* dst_vtx_ptr = (void*) (((uint8_t*)_simgui.vertices.ptr) + all_vtx_size); - memcpy(dst_vtx_ptr, src_vtx_ptr, vtx_size); - } - if (idx_size > 0) { - const ImDrawIdx* src_idx_ptr = cl->IdxBuffer.Data; - void* dst_idx_ptr = (void*) (((uint8_t*)_simgui.indices.ptr) + all_idx_size); - memcpy(dst_idx_ptr, src_idx_ptr, idx_size); - } - all_vtx_size += vtx_size; - all_idx_size += idx_size; - } - if (0 == cmd_list_count) { - return; - } - - // update the sokol-gfx vertex- and index-buffer - sg_push_debug_group("sokol-imgui"); - if (all_vtx_size > 0) { - sg_range vtx_data = _simgui.vertices; - vtx_data.size = all_vtx_size; - sg_update_buffer(_simgui.vbuf, &vtx_data); - } - if (all_idx_size > 0) { - sg_range idx_data = _simgui.indices; - idx_data.size = all_idx_size; - sg_update_buffer(_simgui.ibuf, &idx_data); - } - - // render the ImGui command list - const float dpi_scale = _simgui.cur_dpi_scale; - const int fb_width = (int) (io->DisplaySize.x * dpi_scale); - const int fb_height = (int) (io->DisplaySize.y * dpi_scale); - sg_apply_viewport(0, 0, fb_width, fb_height, true); - sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); - - sg_apply_pipeline(_simgui.def_pip); - _simgui_vs_params_t vs_params; - _simgui_clear((void*)&vs_params, sizeof(vs_params)); - vs_params.disp_size.x = io->DisplaySize.x; - vs_params.disp_size.y = io->DisplaySize.y; - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(vs_params)); - sg_bindings bind; - _simgui_clear((void*)&bind, sizeof(bind)); - bind.vertex_buffers[0] = _simgui.vbuf; - bind.index_buffer = _simgui.ibuf; - ImTextureID tex_id = io->Fonts->TexID; - _simgui_bind_image_sampler(&bind, tex_id); - int vb_offset = 0; - int ib_offset = 0; - for (int cl_index = 0; cl_index < cmd_list_count; cl_index++) { - ImDrawList* cl = _simgui_imdrawlist_at(draw_data, cl_index); - - bind.vertex_buffer_offsets[0] = vb_offset; - bind.index_buffer_offset = ib_offset; - sg_apply_bindings(&bind); - - #if defined(__cplusplus) - const int num_cmds = cl->CmdBuffer.size(); - #else - const int num_cmds = cl->CmdBuffer.Size; - #endif - uint32_t vtx_offset = 0; - for (int cmd_index = 0; cmd_index < num_cmds; cmd_index++) { - ImDrawCmd* pcmd = &cl->CmdBuffer.Data[cmd_index]; - if (pcmd->UserCallback != 0) { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback != ImDrawCallback_ResetRenderState) { - pcmd->UserCallback(cl, pcmd); - // need to re-apply all state after calling a user callback - sg_reset_state_cache(); - sg_apply_viewport(0, 0, fb_width, fb_height, true); - sg_apply_pipeline(_simgui.def_pip); - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(vs_params)); - sg_apply_bindings(&bind); - } - } else { - if ((tex_id != pcmd->TextureId) || (vtx_offset != pcmd->VtxOffset)) { - tex_id = pcmd->TextureId; - vtx_offset = pcmd->VtxOffset; - const _simgui_image_t* img = _simgui_bind_image_sampler(&bind, tex_id); - if (img) { - sg_apply_pipeline(img->pip); - } else { - sg_apply_pipeline(_simgui.def_pip); - } - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(vs_params)); - bind.vertex_buffer_offsets[0] = vb_offset + (int)(pcmd->VtxOffset * sizeof(ImDrawVert)); - sg_apply_bindings(&bind); - } - const int scissor_x = (int) (pcmd->ClipRect.x * dpi_scale); - const int scissor_y = (int) (pcmd->ClipRect.y * dpi_scale); - const int scissor_w = (int) ((pcmd->ClipRect.z - pcmd->ClipRect.x) * dpi_scale); - const int scissor_h = (int) ((pcmd->ClipRect.w - pcmd->ClipRect.y) * dpi_scale); - sg_apply_scissor_rect(scissor_x, scissor_y, scissor_w, scissor_h, true); - sg_draw((int)pcmd->IdxOffset, (int)pcmd->ElemCount, 1); - } - } - #if defined(__cplusplus) - const size_t vtx_size = (size_t)cl->VtxBuffer.size() * sizeof(ImDrawVert); - const size_t idx_size = (size_t)cl->IdxBuffer.size() * sizeof(ImDrawIdx); - #else - const size_t vtx_size = (size_t)cl->VtxBuffer.Size * sizeof(ImDrawVert); - const size_t idx_size = (size_t)cl->IdxBuffer.Size * sizeof(ImDrawIdx); - #endif - vb_offset += (int)vtx_size; - ib_offset += (int)idx_size; - } - sg_apply_viewport(0, 0, fb_width, fb_height, true); - sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); - sg_pop_debug_group(); -} - -SOKOL_API_IMPL void simgui_add_focus_event(bool focus) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - io->AddFocusEvent(focus); - #else - ImGuiIO* io = igGetIO(); - ImGuiIO_AddFocusEvent(io, focus); - #endif -} - -SOKOL_API_IMPL void simgui_add_mouse_pos_event(float x, float y) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_Mouse); - #endif - io->AddMousePosEvent(x, y); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_Mouse); - #endif - ImGuiIO_AddMousePosEvent(io, x, y); - #endif -} - -SOKOL_API_IMPL void simgui_add_touch_pos_event(float x, float y) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); - #endif - io->AddMousePosEvent(x, y); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_TouchScreen); - #endif - ImGuiIO_AddMousePosEvent(io, x, y); - #endif -} - -SOKOL_API_IMPL void simgui_add_mouse_button_event(int mouse_button, bool down) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_Mouse); - #endif - io->AddMouseButtonEvent(mouse_button, down); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_Mouse); - #endif - ImGuiIO_AddMouseButtonEvent(io, mouse_button, down); - #endif -} - -SOKOL_API_IMPL void simgui_add_touch_button_event(int mouse_button, bool down) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); - #endif - io->AddMouseButtonEvent(mouse_button, down); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_TouchScreen); - #endif - ImGuiIO_AddMouseButtonEvent(io, mouse_button, down); - #endif -} - -SOKOL_API_IMPL void simgui_add_mouse_wheel_event(float wheel_x, float wheel_y) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - io->AddMouseSourceEvent(ImGuiMouseSource_Mouse); - #endif - io->AddMouseWheelEvent(wheel_x, wheel_y); - #else - ImGuiIO* io = igGetIO(); - #if (IMGUI_VERSION_NUM >= 18950) - ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_Mouse); - #endif - ImGuiIO_AddMouseWheelEvent(io, wheel_x, wheel_y); - #endif -} - -SOKOL_API_IMPL void simgui_add_key_event(int imgui_key, bool down) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - io->AddKeyEvent((ImGuiKey)imgui_key, down); - #else - ImGuiIO* io = igGetIO(); - ImGuiIO_AddKeyEvent(io, (ImGuiKey)imgui_key, down); - #endif -} - -SOKOL_API_IMPL void simgui_add_input_character(uint32_t c) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - io->AddInputCharacter(c); - #else - ImGuiIO* io = igGetIO(); - ImGuiIO_AddInputCharacter(io, c); - #endif -} - -SOKOL_API_IMPL void simgui_add_input_characters_utf8(const char* c) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - io->AddInputCharactersUTF8(c); - #else - ImGuiIO* io = igGetIO(); - ImGuiIO_AddInputCharactersUTF8(io, c); - #endif -} - -#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) -_SOKOL_PRIVATE bool _simgui_is_ctrl(uint32_t modifiers) { - if (_simgui.is_osx) { - return 0 != (modifiers & SAPP_MODIFIER_SUPER); - } else { - return 0 != (modifiers & SAPP_MODIFIER_CTRL); - } -} - -_SOKOL_PRIVATE ImGuiKey _simgui_map_keycode(sapp_keycode key) { - switch (key) { - case SAPP_KEYCODE_SPACE: return ImGuiKey_Space; - case SAPP_KEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe; - case SAPP_KEYCODE_COMMA: return ImGuiKey_Comma; - case SAPP_KEYCODE_MINUS: return ImGuiKey_Minus; - case SAPP_KEYCODE_PERIOD: return ImGuiKey_Apostrophe; - case SAPP_KEYCODE_SLASH: return ImGuiKey_Slash; - case SAPP_KEYCODE_0: return ImGuiKey_0; - case SAPP_KEYCODE_1: return ImGuiKey_1; - case SAPP_KEYCODE_2: return ImGuiKey_2; - case SAPP_KEYCODE_3: return ImGuiKey_3; - case SAPP_KEYCODE_4: return ImGuiKey_4; - case SAPP_KEYCODE_5: return ImGuiKey_5; - case SAPP_KEYCODE_6: return ImGuiKey_6; - case SAPP_KEYCODE_7: return ImGuiKey_7; - case SAPP_KEYCODE_8: return ImGuiKey_8; - case SAPP_KEYCODE_9: return ImGuiKey_9; - case SAPP_KEYCODE_SEMICOLON: return ImGuiKey_Semicolon; - case SAPP_KEYCODE_EQUAL: return ImGuiKey_Equal; - case SAPP_KEYCODE_A: return ImGuiKey_A; - case SAPP_KEYCODE_B: return ImGuiKey_B; - case SAPP_KEYCODE_C: return ImGuiKey_C; - case SAPP_KEYCODE_D: return ImGuiKey_D; - case SAPP_KEYCODE_E: return ImGuiKey_E; - case SAPP_KEYCODE_F: return ImGuiKey_F; - case SAPP_KEYCODE_G: return ImGuiKey_G; - case SAPP_KEYCODE_H: return ImGuiKey_H; - case SAPP_KEYCODE_I: return ImGuiKey_I; - case SAPP_KEYCODE_J: return ImGuiKey_J; - case SAPP_KEYCODE_K: return ImGuiKey_K; - case SAPP_KEYCODE_L: return ImGuiKey_L; - case SAPP_KEYCODE_M: return ImGuiKey_M; - case SAPP_KEYCODE_N: return ImGuiKey_N; - case SAPP_KEYCODE_O: return ImGuiKey_O; - case SAPP_KEYCODE_P: return ImGuiKey_P; - case SAPP_KEYCODE_Q: return ImGuiKey_Q; - case SAPP_KEYCODE_R: return ImGuiKey_R; - case SAPP_KEYCODE_S: return ImGuiKey_S; - case SAPP_KEYCODE_T: return ImGuiKey_T; - case SAPP_KEYCODE_U: return ImGuiKey_U; - case SAPP_KEYCODE_V: return ImGuiKey_V; - case SAPP_KEYCODE_W: return ImGuiKey_W; - case SAPP_KEYCODE_X: return ImGuiKey_X; - case SAPP_KEYCODE_Y: return ImGuiKey_Y; - case SAPP_KEYCODE_Z: return ImGuiKey_Z; - case SAPP_KEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket; - case SAPP_KEYCODE_BACKSLASH: return ImGuiKey_Backslash; - case SAPP_KEYCODE_RIGHT_BRACKET:return ImGuiKey_RightBracket; - case SAPP_KEYCODE_GRAVE_ACCENT: return ImGuiKey_GraveAccent; - case SAPP_KEYCODE_ESCAPE: return ImGuiKey_Escape; - case SAPP_KEYCODE_ENTER: return ImGuiKey_Enter; - case SAPP_KEYCODE_TAB: return ImGuiKey_Tab; - case SAPP_KEYCODE_BACKSPACE: return ImGuiKey_Backspace; - case SAPP_KEYCODE_INSERT: return ImGuiKey_Insert; - case SAPP_KEYCODE_DELETE: return ImGuiKey_Delete; - case SAPP_KEYCODE_RIGHT: return ImGuiKey_RightArrow; - case SAPP_KEYCODE_LEFT: return ImGuiKey_LeftArrow; - case SAPP_KEYCODE_DOWN: return ImGuiKey_DownArrow; - case SAPP_KEYCODE_UP: return ImGuiKey_UpArrow; - case SAPP_KEYCODE_PAGE_UP: return ImGuiKey_PageUp; - case SAPP_KEYCODE_PAGE_DOWN: return ImGuiKey_PageDown; - case SAPP_KEYCODE_HOME: return ImGuiKey_Home; - case SAPP_KEYCODE_END: return ImGuiKey_End; - case SAPP_KEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock; - case SAPP_KEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock; - case SAPP_KEYCODE_NUM_LOCK: return ImGuiKey_NumLock; - case SAPP_KEYCODE_PRINT_SCREEN: return ImGuiKey_PrintScreen; - case SAPP_KEYCODE_PAUSE: return ImGuiKey_Pause; - case SAPP_KEYCODE_F1: return ImGuiKey_F1; - case SAPP_KEYCODE_F2: return ImGuiKey_F2; - case SAPP_KEYCODE_F3: return ImGuiKey_F3; - case SAPP_KEYCODE_F4: return ImGuiKey_F4; - case SAPP_KEYCODE_F5: return ImGuiKey_F5; - case SAPP_KEYCODE_F6: return ImGuiKey_F6; - case SAPP_KEYCODE_F7: return ImGuiKey_F7; - case SAPP_KEYCODE_F8: return ImGuiKey_F8; - case SAPP_KEYCODE_F9: return ImGuiKey_F9; - case SAPP_KEYCODE_F10: return ImGuiKey_F10; - case SAPP_KEYCODE_F11: return ImGuiKey_F11; - case SAPP_KEYCODE_F12: return ImGuiKey_F12; - case SAPP_KEYCODE_KP_0: return ImGuiKey_Keypad0; - case SAPP_KEYCODE_KP_1: return ImGuiKey_Keypad1; - case SAPP_KEYCODE_KP_2: return ImGuiKey_Keypad2; - case SAPP_KEYCODE_KP_3: return ImGuiKey_Keypad3; - case SAPP_KEYCODE_KP_4: return ImGuiKey_Keypad4; - case SAPP_KEYCODE_KP_5: return ImGuiKey_Keypad5; - case SAPP_KEYCODE_KP_6: return ImGuiKey_Keypad6; - case SAPP_KEYCODE_KP_7: return ImGuiKey_Keypad7; - case SAPP_KEYCODE_KP_8: return ImGuiKey_Keypad8; - case SAPP_KEYCODE_KP_9: return ImGuiKey_Keypad9; - case SAPP_KEYCODE_KP_DECIMAL: return ImGuiKey_KeypadDecimal; - case SAPP_KEYCODE_KP_DIVIDE: return ImGuiKey_KeypadDivide; - case SAPP_KEYCODE_KP_MULTIPLY: return ImGuiKey_KeypadMultiply; - case SAPP_KEYCODE_KP_SUBTRACT: return ImGuiKey_KeypadSubtract; - case SAPP_KEYCODE_KP_ADD: return ImGuiKey_KeypadAdd; - case SAPP_KEYCODE_KP_ENTER: return ImGuiKey_KeypadEnter; - case SAPP_KEYCODE_KP_EQUAL: return ImGuiKey_KeypadEqual; - case SAPP_KEYCODE_LEFT_SHIFT: return ImGuiKey_LeftShift; - case SAPP_KEYCODE_LEFT_CONTROL: return ImGuiKey_LeftCtrl; - case SAPP_KEYCODE_LEFT_ALT: return ImGuiKey_LeftAlt; - case SAPP_KEYCODE_LEFT_SUPER: return ImGuiKey_LeftSuper; - case SAPP_KEYCODE_RIGHT_SHIFT: return ImGuiKey_RightShift; - case SAPP_KEYCODE_RIGHT_CONTROL:return ImGuiKey_RightCtrl; - case SAPP_KEYCODE_RIGHT_ALT: return ImGuiKey_RightAlt; - case SAPP_KEYCODE_RIGHT_SUPER: return ImGuiKey_RightSuper; - case SAPP_KEYCODE_MENU: return ImGuiKey_Menu; - default: return ImGuiKey_None; - } -} - -_SOKOL_PRIVATE void _simgui_add_sapp_key_event(ImGuiIO* io, sapp_keycode sapp_key, bool down) { - const ImGuiKey imgui_key = _simgui_map_keycode(sapp_key); - #if defined(__cplusplus) - io->AddKeyEvent(imgui_key, down); - #else - ImGuiIO_AddKeyEvent(io, imgui_key, down); - #endif -} - -_SOKOL_PRIVATE void _simgui_add_imgui_key_event(ImGuiIO* io, ImGuiKey imgui_key, bool down) { - #if defined(__cplusplus) - io->AddKeyEvent(imgui_key, down); - #else - ImGuiIO_AddKeyEvent(io, imgui_key, down); - #endif -} - -_SOKOL_PRIVATE void _simgui_update_modifiers(ImGuiIO* io, uint32_t mods) { - _simgui_add_imgui_key_event(io, ImGuiMod_Ctrl, (mods & SAPP_MODIFIER_CTRL) != 0); - _simgui_add_imgui_key_event(io, ImGuiMod_Shift, (mods & SAPP_MODIFIER_SHIFT) != 0); - _simgui_add_imgui_key_event(io, ImGuiMod_Alt, (mods & SAPP_MODIFIER_ALT) != 0); - _simgui_add_imgui_key_event(io, ImGuiMod_Super, (mods & SAPP_MODIFIER_SUPER) != 0); -} - -// returns Ctrl or Super, depending on platform -_SOKOL_PRIVATE ImGuiKey _simgui_copypaste_modifier(void) { - return _simgui.is_osx ? ImGuiMod_Super : ImGuiMod_Ctrl; -} - -SOKOL_API_IMPL int simgui_map_keycode(sapp_keycode keycode) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - return (int)_simgui_map_keycode(keycode); -} - -SOKOL_API_IMPL bool simgui_handle_event(const sapp_event* ev) { - SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie); - const float dpi_scale = _simgui.cur_dpi_scale; - #if defined(__cplusplus) - ImGuiIO* io = &ImGui::GetIO(); - #else - ImGuiIO* io = igGetIO(); - #endif - switch (ev->type) { - case SAPP_EVENTTYPE_FOCUSED: - simgui_add_focus_event(true); - break; - case SAPP_EVENTTYPE_UNFOCUSED: - simgui_add_focus_event(false); - break; - case SAPP_EVENTTYPE_MOUSE_DOWN: - simgui_add_mouse_pos_event(ev->mouse_x / dpi_scale, ev->mouse_y / dpi_scale); - simgui_add_mouse_button_event((int)ev->mouse_button, true); - _simgui_update_modifiers(io, ev->modifiers); - break; - case SAPP_EVENTTYPE_MOUSE_UP: - simgui_add_mouse_pos_event(ev->mouse_x / dpi_scale, ev->mouse_y / dpi_scale); - simgui_add_mouse_button_event((int)ev->mouse_button, false); - _simgui_update_modifiers(io, ev->modifiers); - break; - case SAPP_EVENTTYPE_MOUSE_MOVE: - simgui_add_mouse_pos_event(ev->mouse_x / dpi_scale, ev->mouse_y / dpi_scale); - break; - case SAPP_EVENTTYPE_MOUSE_ENTER: - case SAPP_EVENTTYPE_MOUSE_LEAVE: - // FIXME: since the sokol_app.h emscripten backend doesn't support - // mouse capture, mouse buttons must be released when the mouse leaves the - // browser window, so that they don't "stick" when released outside the window. - // A cleaner solution would be a new sokol_app.h function to query - // "platform behaviour flags". - #if defined(__EMSCRIPTEN__) - for (int i = 0; i < SAPP_MAX_MOUSEBUTTONS; i++) { - simgui_add_mouse_button_event(i, false); - } - #endif - break; - case SAPP_EVENTTYPE_MOUSE_SCROLL: - simgui_add_mouse_wheel_event(ev->scroll_x, ev->scroll_y); - break; - case SAPP_EVENTTYPE_TOUCHES_BEGAN: - simgui_add_touch_pos_event(ev->touches[0].pos_x / dpi_scale, ev->touches[0].pos_y / dpi_scale); - simgui_add_touch_button_event(0, true); - break; - case SAPP_EVENTTYPE_TOUCHES_MOVED: - simgui_add_touch_pos_event(ev->touches[0].pos_x / dpi_scale, ev->touches[0].pos_y / dpi_scale); - break; - case SAPP_EVENTTYPE_TOUCHES_ENDED: - simgui_add_touch_pos_event(ev->touches[0].pos_x / dpi_scale, ev->touches[0].pos_y / dpi_scale); - simgui_add_touch_button_event(0, false); - break; - case SAPP_EVENTTYPE_TOUCHES_CANCELLED: - simgui_add_touch_button_event(0, false); - break; - case SAPP_EVENTTYPE_KEY_DOWN: - _simgui_update_modifiers(io, ev->modifiers); - // intercept Ctrl-V, this is handled via EVENTTYPE_CLIPBOARD_PASTED - if (!_simgui.desc.disable_paste_override) { - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_V)) { - break; - } - } - // on web platform, don't forward Ctrl-X, Ctrl-V to the browser - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_X)) { - sapp_consume_event(); - } - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_C)) { - sapp_consume_event(); - } - // it's ok to add ImGuiKey_None key events - _simgui_add_sapp_key_event(io, ev->key_code, true); - break; - case SAPP_EVENTTYPE_KEY_UP: - _simgui_update_modifiers(io, ev->modifiers); - // intercept Ctrl-V, this is handled via EVENTTYPE_CLIPBOARD_PASTED - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_V)) { - break; - } - // on web platform, don't forward Ctrl-X, Ctrl-V to the browser - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_X)) { - sapp_consume_event(); - } - if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_C)) { - sapp_consume_event(); - } - // it's ok to add ImGuiKey_None key events - _simgui_add_sapp_key_event(io, ev->key_code, false); - break; - case SAPP_EVENTTYPE_CHAR: - /* on some platforms, special keys may be reported as - characters, which may confuse some ImGui widgets, - drop those, also don't forward characters if some - modifiers have been pressed - */ - _simgui_update_modifiers(io, ev->modifiers); - if ((ev->char_code >= 32) && - (ev->char_code != 127) && - (0 == (ev->modifiers & (SAPP_MODIFIER_ALT|SAPP_MODIFIER_CTRL|SAPP_MODIFIER_SUPER)))) - { - simgui_add_input_character(ev->char_code); - } - break; - case SAPP_EVENTTYPE_CLIPBOARD_PASTED: - // simulate a Ctrl-V key down/up - if (!_simgui.desc.disable_paste_override) { - _simgui_add_imgui_key_event(io, _simgui_copypaste_modifier(), true); - _simgui_add_imgui_key_event(io, ImGuiKey_V, true); - _simgui_add_imgui_key_event(io, ImGuiKey_V, false); - _simgui_add_imgui_key_event(io, _simgui_copypaste_modifier(), false); - } - break; - default: - break; - } - return io->WantCaptureKeyboard || io->WantCaptureMouse; -} -#endif // SOKOL_IMGUI_NO_SOKOL_APP - -#endif // SOKOL_IMPL diff --git a/source/thirdparty/sokol/util/sokol_memtrack.h b/source/thirdparty/sokol/util/sokol_memtrack.h deleted file mode 100644 index 47f70fca..00000000 --- a/source/thirdparty/sokol/util/sokol_memtrack.h +++ /dev/null @@ -1,167 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_MEMTRACK_IMPL) -#define SOKOL_MEMTRACK_IMPL -#endif -#ifndef SOKOL_MEMTRACK_INCLUDED -/* - sokol_memtrack.h -- memory allocation wrapper to track memory usage - of sokol libraries - - Project URL: https://github.com/floooh/sokol - - Optionally provide the following defines with your own implementations: - - SOKOL_MEMTRACK_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_MEMTRACK_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_memtrack.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - USAGE - ===== - Just plug the malloc/free wrapper functions into the desc.allocator - struct provided by most sokol header setup functions: - - sg_setup(&(sg_desc){ - //... - .allocator = { - .alloc_fn = smemtrack_alloc, - .free_fn = smemtrack_free, - } - }); - - Then call smemtrack_info() to get information about current number - of allocations and overall allocation size: - - const smemtrack_info_t info = smemtrack_info(); - const int num_allocs = info.num_allocs; - const int num_bytes = info.num_bytes; - - Note the sokol_memtrack.h can only track allocations issued by - the sokol headers, not allocations that happen under the hood - in system libraries. - - 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. -*/ -#define SOKOL_MEMTRACK_INCLUDED (1) -#include -#include // size_t - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_MEMTRACK_API_DECL) -#define SOKOL_MEMTRACK_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_MEMTRACK_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_MEMTRACK_IMPL) -#define SOKOL_MEMTRACK_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_MEMTRACK_API_DECL __declspec(dllimport) -#else -#define SOKOL_MEMTRACK_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct smemtrack_info_t { - int num_allocs; - int num_bytes; -} smemtrack_info_t; - -SOKOL_MEMTRACK_API_DECL smemtrack_info_t smemtrack_info(void); -SOKOL_MEMTRACK_API_DECL void* smemtrack_alloc(size_t size, void* user_data); -SOKOL_MEMTRACK_API_DECL void smemtrack_free(void* ptr, void* user_data); - -#ifdef __cplusplus -} /* extern "C" */ -#endif -#endif /* SOKOL_MEMTRACK_INCLUDED */ - -/*=== IMPLEMENTATION =========================================================*/ -#ifdef SOKOL_MEMTRACK_IMPL -#define SOKOL_MEMTRACK_IMPL_INCLUDED (1) -#include // malloc, free -#include // memset - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG - #endif -#endif -#ifndef _SOKOL_PRIVATE - #if defined(__GNUC__) || defined(__clang__) - #define _SOKOL_PRIVATE __attribute__((unused)) static - #else - #define _SOKOL_PRIVATE static - #endif -#endif - -// per-allocation header used to keep track of the allocation size -#define _SMEMTRACK_HEADER_SIZE (16) - -static struct { - smemtrack_info_t state; -} _smemtrack; - -SOKOL_API_IMPL void* smemtrack_alloc(size_t size, void* user_data) { - (void)user_data; - uint8_t* ptr = (uint8_t*) malloc(size + _SMEMTRACK_HEADER_SIZE); - if (ptr) { - // store allocation size (for allocation size tracking) - *(size_t*)ptr = size; - _smemtrack.state.num_allocs++; - _smemtrack.state.num_bytes += (int) size; - return ptr + _SMEMTRACK_HEADER_SIZE; - } - else { - // allocation failed, return null pointer - return ptr; - } -} - -SOKOL_API_IMPL void smemtrack_free(void* ptr, void* user_data) { - (void)user_data; - if (ptr) { - uint8_t* alloc_ptr = ((uint8_t*)ptr) - _SMEMTRACK_HEADER_SIZE; - size_t size = *(size_t*)alloc_ptr; - _smemtrack.state.num_allocs--; - _smemtrack.state.num_bytes -= (int) size; - free(alloc_ptr); - } -} - -SOKOL_API_IMPL smemtrack_info_t smemtrack_info(void) { - return _smemtrack.state; -} - -#endif /* SOKOL_MEMTRACK_IMPL */ diff --git a/source/thirdparty/sokol/util/sokol_shape.h b/source/thirdparty/sokol/util/sokol_shape.h deleted file mode 100644 index d1676dd3..00000000 --- a/source/thirdparty/sokol/util/sokol_shape.h +++ /dev/null @@ -1,1431 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_SHAPE_IMPL) -#define SOKOL_SHAPE_IMPL -#endif -#ifndef SOKOL_SHAPE_INCLUDED -/* - sokol_shape.h -- create simple primitive shapes for sokol_gfx.h - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_SHAPE_IMPL - before you include this file in *one* C or C++ file to create the - implementation. - - Include the following headers before including sokol_shape.h: - - sokol_gfx.h - - ...optionally provide the following macros to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_SHAPE_API_DECL- public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_SHAPE_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - - If sokol_shape.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_SHAPE_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - FEATURE OVERVIEW - ================ - sokol_shape.h creates vertices and indices for simple shapes and - builds structs which can be plugged into sokol-gfx resource - creation functions: - - The following shape types are supported: - - - plane - - cube - - sphere (with poles, not geodesic) - - cylinder - - torus (donut) - - Generated vertices look like this: - - typedef struct sshape_vertex_t { - float x, y, z; - uint32_t normal; // packed normal as BYTE4N - uint16_t u, v; // packed uv coords as USHORT2N - uint32_t color; // packed color as UBYTE4N (r,g,b,a); - } sshape_vertex_t; - - Indices are generally 16-bits wide (SG_INDEXTYPE_UINT16) and the indices - are written as triangle-lists (SG_PRIMITIVETYPE_TRIANGLES). - - EXAMPLES: - ========= - - Create multiple shapes into the same vertex- and index-buffer and - render with separate draw calls: - - https://github.com/floooh/sokol-samples/blob/master/sapp/shapes-sapp.c - - Same as the above, but pre-transform shapes and merge them into a single - shape that's rendered with a single draw call. - - https://github.com/floooh/sokol-samples/blob/master/sapp/shapes-transform-sapp.c - - STEP-BY-STEP: - ============= - - Setup an sshape_buffer_t struct with pointers to memory buffers where - generated vertices and indices will be written to: - - ```c - sshape_vertex_t vertices[512]; - uint16_t indices[4096]; - - sshape_buffer_t buf = { - .vertices = { - .buffer = SSHAPE_RANGE(vertices), - }, - .indices = { - .buffer = SSHAPE_RANGE(indices), - } - }; - ``` - - To find out how big those memory buffers must be (in case you want - to allocate dynamically) call the following functions: - - ```c - sshape_sizes_t sshape_plane_sizes(uint32_t tiles); - sshape_sizes_t sshape_box_sizes(uint32_t tiles); - sshape_sizes_t sshape_sphere_sizes(uint32_t slices, uint32_t stacks); - sshape_sizes_t sshape_cylinder_sizes(uint32_t slices, uint32_t stacks); - sshape_sizes_t sshape_torus_sizes(uint32_t sides, uint32_t rings); - ``` - - The returned sshape_sizes_t struct contains vertex- and index-counts - as well as the equivalent buffer sizes in bytes. For instance: - - ```c - sshape_sizes_t sizes = sshape_sphere_sizes(36, 12); - uint32_t num_vertices = sizes.vertices.num; - uint32_t num_indices = sizes.indices.num; - uint32_t vertex_buffer_size = sizes.vertices.size; - uint32_t index_buffer_size = sizes.indices.size; - ``` - - With the sshape_buffer_t struct that was setup earlier, call any - of the shape-builder functions: - - ```c - sshape_buffer_t sshape_build_plane(const sshape_buffer_t* buf, const sshape_plane_t* params); - sshape_buffer_t sshape_build_box(const sshape_buffer_t* buf, const sshape_box_t* params); - sshape_buffer_t sshape_build_sphere(const sshape_buffer_t* buf, const sshape_sphere_t* params); - sshape_buffer_t sshape_build_cylinder(const sshape_buffer_t* buf, const sshape_cylinder_t* params); - sshape_buffer_t sshape_build_torus(const sshape_buffer_t* buf, const sshape_torus_t* params); - ``` - - Note how the sshape_buffer_t struct is both an input value and the - return value. This can be used to append multiple shapes into the - same vertex- and index-buffers (more on this later). - - The second argument is a struct which holds creation parameters. - - For instance to build a sphere with radius 2, 36 "cake slices" and 12 stacks: - - ```c - sshape_buffer_t buf = ...; - buf = sshape_build_sphere(&buf, &(sshape_sphere_t){ - .radius = 2.0f, - .slices = 36, - .stacks = 12, - }); - ``` - - If the provided buffers are big enough to hold all generated vertices and - indices, the "valid" field in the result will be true: - - ```c - assert(buf.valid); - ``` - - The shape creation parameters have "useful defaults", refer to the - actual C struct declarations below to look up those defaults. - - You can also provide additional creation parameters, like a common vertex - color, a debug-helper to randomize colors, tell the shape builder function - to merge the new shape with the previous shape into the same draw-element-range, - or a 4x4 transform matrix to move, rotate and scale the generated vertices: - - ```c - sshape_buffer_t buf = ...; - buf = sshape_build_sphere(&buf, &(sshape_sphere_t){ - .radius = 2.0f, - .slices = 36, - .stacks = 12, - // merge with previous shape into a single element-range - .merge = true, - // set vertex color to red+opaque - .color = sshape_color_4f(1.0f, 0.0f, 0.0f, 1.0f), - // set position to y = 2.0 - .transform = { - .m = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 2.0f, 0.0f, 1.0f }, - } - } - }); - assert(buf.valid); - ``` - - The following helper functions can be used to build a packed - color value or to convert from external matrix types: - - ```c - uint32_t sshape_color_4f(float r, float g, float b, float a); - uint32_t sshape_color_3f(float r, float g, float b); - uint32_t sshape_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); - uint32_t sshape_color_3b(uint8_t r, uint8_t g, uint8_t b); - sshape_mat4_t sshape_mat4(const float m[16]); - sshape_mat4_t sshape_mat4_transpose(const float m[16]); - ``` - - After the shape builder function has been called, the following functions - are used to extract the build result for plugging into sokol_gfx.h: - - ```c - sshape_element_range_t sshape_element_range(const sshape_buffer_t* buf); - sg_buffer_desc sshape_vertex_buffer_desc(const sshape_buffer_t* buf); - sg_buffer_desc sshape_index_buffer_desc(const sshape_buffer_t* buf); - sg_vertex_buffer_layout_state sshape_vertex_buffer_layout_state(void); - sg_vertex_attr_state sshape_position_vertex_attr_state(void); - sg_vertex_attr_state sshape_normal_vertex_attr_state(void); - sg_vertex_attr_state sshape_texcoord_vertex_attr_state(void); - sg_vertex_attr_state sshape_color_vertex_attr_state(void); - ``` - - The sshape_element_range_t struct contains the base-index and number of - indices which can be plugged into the sg_draw() call: - - ```c - sshape_element_range_t elms = sshape_element_range(&buf); - ... - sg_draw(elms.base_element, elms.num_elements, 1); - ``` - - To create sokol-gfx vertex- and index-buffers from the generated - shape data: - - ```c - // create sokol-gfx vertex buffer - sg_buffer_desc vbuf_desc = sshape_vertex_buffer_desc(&buf); - sg_buffer vbuf = sg_make_buffer(&vbuf_desc); - - // create sokol-gfx index buffer - sg_buffer_desc ibuf_desc = sshape_index_buffer_desc(&buf); - sg_buffer ibuf = sg_make_buffer(&ibuf_desc); - ``` - - The remaining functions are used to populate the vertex-layout item - in sg_pipeline_desc, note that these functions don't depend on the - created geometry, they always return the same result: - - ```c - sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){ - .layout = { - .buffers[0] = sshape_vertex_buffer_layout_state(), - .attrs = { - [0] = sshape_position_vertex_attr_state(), - [1] = ssape_normal_vertex_attr_state(), - [2] = sshape_texcoord_vertex_attr_state(), - [3] = sshape_color_vertex_attr_state() - } - }, - ... - }); - ``` - - Note that you don't have to use all generated vertex attributes in the - pipeline's vertex layout, the sg_vertex_buffer_layout_state struct returned - by sshape_vertex_buffer_layout_state() contains the correct vertex stride - to skip vertex components. - - WRITING MULTIPLE SHAPES INTO THE SAME BUFFER - ============================================ - You can merge multiple shapes into the same vertex- and - index-buffers and either render them as a single shape, or - in separate draw calls. - - To build a single shape made of two cubes which can be rendered - in a single draw-call: - - ``` - sshape_vertex_t vertices[128]; - uint16_t indices[16]; - - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vertices), - .indices.buffer = SSHAPE_RANGE(indices) - }; - - // first cube at pos x=-2.0 (with default size of 1x1x1) - buf = sshape_build_cube(&buf, &(sshape_box_t){ - .transform = { - .m = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - {-2.0f, 0.0f, 0.0f, 1.0f }, - } - } - }); - // ...and append another cube at pos pos=+1.0 - // NOTE the .merge = true, this tells the shape builder - // function to not advance the current shape start offset - buf = sshape_build_cube(&buf, &(sshape_box_t){ - .merge = true, - .transform = { - .m = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - {-2.0f, 0.0f, 0.0f, 1.0f }, - } - } - }); - assert(buf.valid); - - // skipping buffer- and pipeline-creation... - - sshape_element_range_t elms = sshape_element_range(&buf); - sg_draw(elms.base_element, elms.num_elements, 1); - ``` - - To render the two cubes in separate draw-calls, the element-ranges used - in the sg_draw() calls must be captured right after calling the - builder-functions: - - ```c - sshape_vertex_t vertices[128]; - uint16_t indices[16]; - sshape_buffer_t buf = { - .vertices.buffer = SSHAPE_RANGE(vertices), - .indices.buffer = SSHAPE_RANGE(indices) - }; - - // build a red cube... - buf = sshape_build_cube(&buf, &(sshape_box_t){ - .color = sshape_color_3b(255, 0, 0) - }); - sshape_element_range_t red_cube = sshape_element_range(&buf); - - // append a green cube to the same vertex-/index-buffer: - buf = sshape_build_cube(&bud, &sshape_box_t){ - .color = sshape_color_3b(0, 255, 0); - }); - sshape_element_range_t green_cube = sshape_element_range(&buf); - - // skipping buffer- and pipeline-creation... - - sg_draw(red_cube.base_element, red_cube.num_elements, 1); - sg_draw(green_cube.base_element, green_cube.num_elements, 1); - ``` - - ...that's about all :) - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2020 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. -*/ -#define SOKOL_SHAPE_INCLUDED -#include // size_t, offsetof -#include -#include - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_shape.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_SHAPE_API_DECL) -#define SOKOL_SHAPE_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_SHAPE_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_SHAPE_IMPL) -#define SOKOL_SHAPE_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_SHAPE_API_DECL __declspec(dllimport) -#else -#define SOKOL_SHAPE_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - sshape_range is a pointer-size-pair struct used to pass memory - blobs into sokol-shape. When initialized from a value type - (array or struct), use the SSHAPE_RANGE() macro to build - an sshape_range struct. -*/ -typedef struct sshape_range { - const void* ptr; - size_t size; -} sshape_range; - -// disabling this for every includer isn't great, but the warning is also quite pointless -#if defined(_MSC_VER) -#pragma warning(disable:4221) /* /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' */ -#endif -#if defined(__cplusplus) -#define SSHAPE_RANGE(x) sshape_range{ &x, sizeof(x) } -#else -#define SSHAPE_RANGE(x) (sshape_range){ &x, sizeof(x) } -#endif - -/* a 4x4 matrix wrapper struct */ -typedef struct sshape_mat4_t { float m[4][4]; } sshape_mat4_t; - -/* vertex layout of the generated geometry */ -typedef struct sshape_vertex_t { - float x, y, z; - uint32_t normal; // packed normal as BYTE4N - uint16_t u, v; // packed uv coords as USHORT2N - uint32_t color; // packed color as UBYTE4N (r,g,b,a); -} sshape_vertex_t; - -/* a range of draw-elements (sg_draw(int base_element, int num_element, ...)) */ -typedef struct sshape_element_range_t { - int base_element; - int num_elements; -} sshape_element_range_t; - -/* number of elements and byte size of build actions */ -typedef struct sshape_sizes_item_t { - uint32_t num; // number of elements - uint32_t size; // the same as size in bytes -} sshape_sizes_item_t; - -typedef struct sshape_sizes_t { - sshape_sizes_item_t vertices; - sshape_sizes_item_t indices; -} sshape_sizes_t; - -/* in/out struct to keep track of mesh-build state */ -typedef struct sshape_buffer_item_t { - sshape_range buffer; // pointer/size pair of output buffer - size_t data_size; // size in bytes of valid data in buffer - size_t shape_offset; // data offset of the most recent shape -} sshape_buffer_item_t; - -typedef struct sshape_buffer_t { - bool valid; - sshape_buffer_item_t vertices; - sshape_buffer_item_t indices; -} sshape_buffer_t; - -/* creation parameters for the different shape types */ -typedef struct sshape_plane_t { - float width, depth; // default: 1.0 - uint16_t tiles; // default: 1 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_plane_t; - -typedef struct sshape_box_t { - float width, height, depth; // default: 1.0 - uint16_t tiles; // default: 1 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_box_t; - -typedef struct sshape_sphere_t { - float radius; // default: 0.5 - uint16_t slices; // default: 5 - uint16_t stacks; // default: 4 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_sphere_t; - -typedef struct sshape_cylinder_t { - float radius; // default: 0.5 - float height; // default: 1.0 - uint16_t slices; // default: 5 - uint16_t stacks; // default: 1 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_cylinder_t; - -typedef struct sshape_torus_t { - float radius; // default: 0.5f - float ring_radius; // default: 0.2f - uint16_t sides; // default: 5 - uint16_t rings; // default: 5 - uint32_t color; // default: white - bool random_colors; // default: false - bool merge; // if true merge with previous shape (default: false) - sshape_mat4_t transform; // default: identity matrix -} sshape_torus_t; - -/* shape builder functions */ -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_plane(const sshape_buffer_t* buf, const sshape_plane_t* params); -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_box(const sshape_buffer_t* buf, const sshape_box_t* params); -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_sphere(const sshape_buffer_t* buf, const sshape_sphere_t* params); -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_cylinder(const sshape_buffer_t* buf, const sshape_cylinder_t* params); -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_torus(const sshape_buffer_t* buf, const sshape_torus_t* params); - -/* query required vertex- and index-buffer sizes in bytes */ -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_plane_sizes(uint32_t tiles); -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_box_sizes(uint32_t tiles); -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_sphere_sizes(uint32_t slices, uint32_t stacks); -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_cylinder_sizes(uint32_t slices, uint32_t stacks); -SOKOL_SHAPE_API_DECL sshape_sizes_t sshape_torus_sizes(uint32_t sides, uint32_t rings); - -/* extract sokol-gfx desc structs and primitive ranges from build state */ -SOKOL_SHAPE_API_DECL sshape_element_range_t sshape_element_range(const sshape_buffer_t* buf); -SOKOL_SHAPE_API_DECL sg_buffer_desc sshape_vertex_buffer_desc(const sshape_buffer_t* buf); -SOKOL_SHAPE_API_DECL sg_buffer_desc sshape_index_buffer_desc(const sshape_buffer_t* buf); -SOKOL_SHAPE_API_DECL sg_vertex_buffer_layout_state sshape_vertex_buffer_layout_state(void); -SOKOL_SHAPE_API_DECL sg_vertex_attr_state sshape_position_vertex_attr_state(void); -SOKOL_SHAPE_API_DECL sg_vertex_attr_state sshape_normal_vertex_attr_state(void); -SOKOL_SHAPE_API_DECL sg_vertex_attr_state sshape_texcoord_vertex_attr_state(void); -SOKOL_SHAPE_API_DECL sg_vertex_attr_state sshape_color_vertex_attr_state(void); - -/* helper functions to build packed color value from floats or bytes */ -SOKOL_SHAPE_API_DECL uint32_t sshape_color_4f(float r, float g, float b, float a); -SOKOL_SHAPE_API_DECL uint32_t sshape_color_3f(float r, float g, float b); -SOKOL_SHAPE_API_DECL uint32_t sshape_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_SHAPE_API_DECL uint32_t sshape_color_3b(uint8_t r, uint8_t g, uint8_t b); - -/* adapter function for filling matrix struct from generic float[16] array */ -SOKOL_SHAPE_API_DECL sshape_mat4_t sshape_mat4(const float m[16]); -SOKOL_SHAPE_API_DECL sshape_mat4_t sshape_mat4_transpose(const float m[16]); - -#ifdef __cplusplus -} // extern "C" - -// FIXME: C++ helper functions - -#endif -#endif // SOKOL_SHAPE_INCLUDED - -/*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_SHAPE_IMPL -#define SOKOL_SHAPE_IMPL_INCLUDED (1) - -#include // memcpy -#include // sinf, cosf - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-field-initializers" -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif - -#define _sshape_def(val, def) (((val) == 0) ? (def) : (val)) -#define _sshape_def_flt(val, def) (((val) == 0.0f) ? (def) : (val)) -#define _sshape_white (0xFFFFFFFF) - -typedef struct { float x, y, z, w; } _sshape_vec4_t; -typedef struct { float x, y; } _sshape_vec2_t; - -static inline float _sshape_clamp(float v) { - if (v < 0.0f) return 0.0f; - else if (v > 1.0f) return 1.0f; - else return v; -} - -static inline uint32_t _sshape_pack_ub4_ubyte4n(uint8_t x, uint8_t y, uint8_t z, uint8_t w) { - return (uint32_t)(((uint32_t)w<<24)|((uint32_t)z<<16)|((uint32_t)y<<8)|x); -} - -static inline uint32_t _sshape_pack_f4_ubyte4n(float x, float y, float z, float w) { - uint8_t x8 = (uint8_t) (x * 255.0f); - uint8_t y8 = (uint8_t) (y * 255.0f); - uint8_t z8 = (uint8_t) (z * 255.0f); - uint8_t w8 = (uint8_t) (w * 255.0f); - return _sshape_pack_ub4_ubyte4n(x8, y8, z8, w8); -} - -static inline uint32_t _sshape_pack_f4_byte4n(float x, float y, float z, float w) { - int8_t x8 = (int8_t) (x * 127.0f); - int8_t y8 = (int8_t) (y * 127.0f); - int8_t z8 = (int8_t) (z * 127.0f); - int8_t w8 = (int8_t) (w * 127.0f); - return _sshape_pack_ub4_ubyte4n((uint8_t)x8, (uint8_t)y8, (uint8_t)z8, (uint8_t)w8); -} - -static inline uint16_t _sshape_pack_f_ushortn(float x) { - return (uint16_t) (x * 65535.0f); -} - -static inline _sshape_vec4_t _sshape_vec4(float x, float y, float z, float w) { - _sshape_vec4_t v = { x, y, z, w }; - return v; -} - -static inline _sshape_vec4_t _sshape_vec4_norm(_sshape_vec4_t v) { - float l = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w); - if (l != 0.0f) { - return _sshape_vec4(v.x/l, v.y/l, v.z/l, v.w/l); - } - else { - return _sshape_vec4(0.0f, 1.0f, 0.0f, 0.0f); - } -} - -static inline _sshape_vec2_t _sshape_vec2(float x, float y) { - _sshape_vec2_t v = { x, y }; - return v; -} - -static bool _sshape_mat4_isnull(const sshape_mat4_t* m) { - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 4; x++) { - if (0.0f != m->m[y][x]) { - return false; - } - } - } - return true; -} - -static sshape_mat4_t _sshape_mat4_identity(void) { - sshape_mat4_t m = { - { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 1.0f } - } - }; - return m; -} - -static _sshape_vec4_t _sshape_mat4_mul(const sshape_mat4_t* m, _sshape_vec4_t v) { - _sshape_vec4_t res = { - m->m[0][0]*v.x + m->m[1][0]*v.y + m->m[2][0]*v.z + m->m[3][0]*v.w, - m->m[0][1]*v.x + m->m[1][1]*v.y + m->m[2][1]*v.z + m->m[3][1]*v.w, - m->m[0][2]*v.x + m->m[1][2]*v.y + m->m[2][2]*v.z + m->m[3][2]*v.w, - m->m[0][3]*v.x + m->m[1][3]*v.y + m->m[2][3]*v.z + m->m[3][3]*v.w - }; - return res; -} - -static uint32_t _sshape_plane_num_vertices(uint32_t tiles) { - return (tiles + 1) * (tiles + 1); -} - -static uint32_t _sshape_plane_num_indices(uint32_t tiles) { - return tiles * tiles * 2 * 3; -} - -static uint32_t _sshape_box_num_vertices(uint32_t tiles) { - return (tiles + 1) * (tiles + 1) * 6; -} - -static uint32_t _sshape_box_num_indices(uint32_t tiles) { - return tiles * tiles * 2 * 6 * 3; -} - -static uint32_t _sshape_sphere_num_vertices(uint32_t slices, uint32_t stacks) { - return (slices + 1) * (stacks + 1); -} - -static uint32_t _sshape_sphere_num_indices(uint32_t slices, uint32_t stacks) { - return ((2 * slices * stacks) - (2 * slices)) * 3; -} - -static uint32_t _sshape_cylinder_num_vertices(uint32_t slices, uint32_t stacks) { - return (slices + 1) * (stacks + 5); -} - -static uint32_t _sshape_cylinder_num_indices(uint32_t slices, uint32_t stacks) { - return ((2 * slices * stacks) + (2 * slices)) * 3; -} - -static uint32_t _sshape_torus_num_vertices(uint32_t sides, uint32_t rings) { - return (sides + 1) * (rings + 1); -} - -static uint32_t _sshape_torus_num_indices(uint32_t sides, uint32_t rings) { - return sides * rings * 2 * 3; -} - -static bool _sshape_validate_buffer_item(const sshape_buffer_item_t* item, uint32_t build_size) { - if (0 == item->buffer.ptr) { - return false; - } - if (0 == item->buffer.size) { - return false; - } - if ((item->data_size + build_size) > item->buffer.size) { - return false; - } - if (item->shape_offset > item->data_size) { - return false; - } - return true; -} - -static bool _sshape_validate_buffer(const sshape_buffer_t* buf, uint32_t num_vertices, uint32_t num_indices) { - if (!_sshape_validate_buffer_item(&buf->vertices, num_vertices * sizeof(sshape_vertex_t))) { - return false; - } - if (!_sshape_validate_buffer_item(&buf->indices, num_indices * sizeof(uint16_t))) { - return false; - } - return true; -} - -static void _sshape_advance_offset(sshape_buffer_item_t* item) { - item->shape_offset = item->data_size; -} - -static uint16_t _sshape_base_index(const sshape_buffer_t* buf) { - return (uint16_t) (buf->vertices.data_size / sizeof(sshape_vertex_t)); -} - -static sshape_plane_t _sshape_plane_defaults(const sshape_plane_t* params) { - sshape_plane_t res = *params; - res.width = _sshape_def_flt(res.width, 1.0f); - res.depth = _sshape_def_flt(res.depth, 1.0f); - res.tiles = _sshape_def(res.tiles, 1); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static sshape_box_t _sshape_box_defaults(const sshape_box_t* params) { - sshape_box_t res = *params; - res.width = _sshape_def_flt(res.width, 1.0f); - res.height = _sshape_def_flt(res.height, 1.0f); - res.depth = _sshape_def_flt(res.depth, 1.0f); - res.tiles = _sshape_def(res.tiles, 1); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static sshape_sphere_t _sshape_sphere_defaults(const sshape_sphere_t* params) { - sshape_sphere_t res = *params; - res.radius = _sshape_def_flt(res.radius, 0.5f); - res.slices = _sshape_def(res.slices, 5); - res.stacks = _sshape_def(res.stacks, 4); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static sshape_cylinder_t _sshape_cylinder_defaults(const sshape_cylinder_t* params) { - sshape_cylinder_t res = *params; - res.radius = _sshape_def_flt(res.radius, 0.5f); - res.height = _sshape_def_flt(res.height, 1.0f); - res.slices = _sshape_def(res.slices, 5); - res.stacks = _sshape_def(res.stacks, 1); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static sshape_torus_t _sshape_torus_defaults(const sshape_torus_t* params) { - sshape_torus_t res = *params; - res.radius = _sshape_def_flt(res.radius, 0.5f); - res.ring_radius = _sshape_def_flt(res.ring_radius, 0.2f); - res.sides = _sshape_def_flt(res.sides, 5); - res.rings = _sshape_def_flt(res.rings, 5); - res.color = _sshape_def(res.color, _sshape_white); - res.transform = _sshape_mat4_isnull(&res.transform) ? _sshape_mat4_identity() : res.transform; - return res; -} - -static void _sshape_add_vertex(sshape_buffer_t* buf, _sshape_vec4_t pos, _sshape_vec4_t norm, _sshape_vec2_t uv, uint32_t color) { - size_t offset = buf->vertices.data_size; - SOKOL_ASSERT((offset + sizeof(sshape_vertex_t)) <= buf->vertices.buffer.size); - buf->vertices.data_size += sizeof(sshape_vertex_t); - sshape_vertex_t* v_ptr = (sshape_vertex_t*) ((uint8_t*)buf->vertices.buffer.ptr + offset); - v_ptr->x = pos.x; - v_ptr->y = pos.y; - v_ptr->z = pos.z; - v_ptr->normal = _sshape_pack_f4_byte4n(norm.x, norm.y, norm.z, norm.w); - v_ptr->u = _sshape_pack_f_ushortn(uv.x); - v_ptr->v = _sshape_pack_f_ushortn(uv.y); - v_ptr->color = color; -} - -static void _sshape_add_triangle(sshape_buffer_t* buf, uint16_t i0, uint16_t i1, uint16_t i2) { - size_t offset = buf->indices.data_size; - SOKOL_ASSERT((offset + 3*sizeof(uint16_t)) <= buf->indices.buffer.size); - buf->indices.data_size += 3*sizeof(uint16_t); - uint16_t* i_ptr = (uint16_t*) ((uint8_t*)buf->indices.buffer.ptr + offset); - i_ptr[0] = i0; - i_ptr[1] = i1; - i_ptr[2] = i2; -} - -static uint32_t _sshape_rand_color(uint32_t* xorshift_state) { - // xorshift32 - uint32_t x = *xorshift_state; - x ^= x<<13; - x ^= x>>17; - x ^= x<<5; - *xorshift_state = x; - - // rand => bright color with alpha 1.0 - x |= 0xFF000000; - return x; - -} - -/*=== PUBLIC API FUNCTIONS ===================================================*/ -SOKOL_API_IMPL uint32_t sshape_color_4f(float r, float g, float b, float a) { - return _sshape_pack_f4_ubyte4n(_sshape_clamp(r), _sshape_clamp(g), _sshape_clamp(b), _sshape_clamp(a)); -} - -SOKOL_API_IMPL uint32_t sshape_color_3f(float r, float g, float b) { - return _sshape_pack_f4_ubyte4n(_sshape_clamp(r), _sshape_clamp(g), _sshape_clamp(b), 1.0f); -} - -SOKOL_API_IMPL uint32_t sshape_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return _sshape_pack_ub4_ubyte4n(r, g, b, a); -} - -SOKOL_API_IMPL uint32_t sshape_color_3b(uint8_t r, uint8_t g, uint8_t b) { - return _sshape_pack_ub4_ubyte4n(r, g, b, 255); -} - -SOKOL_API_IMPL sshape_mat4_t sshape_mat4(const float m[16]) { - sshape_mat4_t res; - memcpy(&res.m[0][0], &m[0], 64); - return res; -} - -SOKOL_API_IMPL sshape_mat4_t sshape_mat4_transpose(const float m[16]) { - sshape_mat4_t res; - for (int c = 0; c < 4; c++) { - for (int r = 0; r < 4; r++) { - res.m[r][c] = m[c*4 + r]; - } - } - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_plane_sizes(uint32_t tiles) { - SOKOL_ASSERT(tiles >= 1); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_plane_num_vertices(tiles); - res.indices.num = _sshape_plane_num_indices(tiles); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_box_sizes(uint32_t tiles) { - SOKOL_ASSERT(tiles >= 1); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_box_num_vertices(tiles); - res.indices.num = _sshape_box_num_indices(tiles); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_sphere_sizes(uint32_t slices, uint32_t stacks) { - SOKOL_ASSERT((slices >= 3) && (stacks >= 2)); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_sphere_num_vertices(slices, stacks); - res.indices.num = _sshape_sphere_num_indices(slices, stacks); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_cylinder_sizes(uint32_t slices, uint32_t stacks) { - SOKOL_ASSERT((slices >= 3) && (stacks >= 1)); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_cylinder_num_vertices(slices, stacks); - res.indices.num = _sshape_cylinder_num_indices(slices, stacks); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -SOKOL_API_IMPL sshape_sizes_t sshape_torus_sizes(uint32_t sides, uint32_t rings) { - SOKOL_ASSERT((sides >= 3) && (rings >= 3)); - sshape_sizes_t res = { {0} }; - res.vertices.num = _sshape_torus_num_vertices(sides, rings); - res.indices.num = _sshape_torus_num_indices(sides, rings); - res.vertices.size = res.vertices.num * sizeof(sshape_vertex_t); - res.indices.size = res.indices.num * sizeof(uint16_t); - return res; -} - -/* - Geometry layout for plane (4 tiles): - +--+--+--+--+ - |\ |\ |\ |\ | - | \| \| \| \| - +--+--+--+--+ 25 vertices (tiles + 1) * (tiles + 1) - |\ |\ |\ |\ | 32 triangles (tiles + 1) * (tiles + 1) * 2 - | \| \| \| \| - +--+--+--+--+ - |\ |\ |\ |\ | - | \| \| \| \| - +--+--+--+--+ - |\ |\ |\ |\ | - | \| \| \| \| - +--+--+--+--+ -*/ -SOKOL_API_IMPL sshape_buffer_t sshape_build_plane(const sshape_buffer_t* in_buf, const sshape_plane_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_plane_t params = _sshape_plane_defaults(in_params); - const uint32_t num_vertices = _sshape_plane_num_vertices(params.tiles); - const uint32_t num_indices = _sshape_plane_num_indices(params.tiles); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - // write vertices - uint32_t rand_seed = 0x12345678; - const float x0 = -params.width * 0.5f; - const float z0 = params.depth * 0.5f; - const float dx = params.width / params.tiles; - const float dz = -params.depth / params.tiles; - const float duv = 1.0f / params.tiles; - _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, _sshape_vec4(0.0f, 1.0f, 0.0f, 0.0f))); - for (uint32_t ix = 0; ix <= params.tiles; ix++) { - for (uint32_t iz = 0; iz <= params.tiles; iz++) { - const _sshape_vec4_t pos = _sshape_vec4(x0 + dx*ix, 0.0f, z0 + dz*iz, 1.0f); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(duv*ix, duv*iz); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - - // write indices - for (uint16_t j = 0; j < params.tiles; j++) { - for (uint16_t i = 0; i < params.tiles; i++) { - const uint16_t i0 = start_index + (j * (params.tiles + 1)) + i; - const uint16_t i1 = i0 + 1; - const uint16_t i2 = i0 + params.tiles + 1; - const uint16_t i3 = i2 + 1; - _sshape_add_triangle(&buf, i0, i1, i3); - _sshape_add_triangle(&buf, i0, i3, i2); - } - } - return buf; -} - -SOKOL_API_IMPL sshape_buffer_t sshape_build_box(const sshape_buffer_t* in_buf, const sshape_box_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_box_t params = _sshape_box_defaults(in_params); - const uint32_t num_vertices = _sshape_box_num_vertices(params.tiles); - const uint32_t num_indices = _sshape_box_num_indices(params.tiles); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - // build vertices - uint32_t rand_seed = 0x12345678; - const float x0 = -params.width * 0.5f; - const float x1 = params.width * 0.5f; - const float y0 = -params.height * 0.5f; - const float y1 = params.height * 0.5f; - const float z0 = -params.depth * 0.5f; - const float z1 = params.depth * 0.5f; - const float dx = params.width / params.tiles; - const float dy = params.height / params.tiles; - const float dz = params.depth / params.tiles; - const float duv = 1.0f / params.tiles; - - // bottom/top vertices - for (uint32_t top_bottom = 0; top_bottom < 2; top_bottom++) { - _sshape_vec4_t pos = _sshape_vec4(0.0f, (0==top_bottom) ? y0:y1, 0.0f, 1.0f); - const _sshape_vec4_t norm = _sshape_vec4(0.0f, (0==top_bottom) ? -1.0f:1.0f, 0.0f, 0.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - for (uint32_t ix = 0; ix <= params.tiles; ix++) { - pos.x = (0==top_bottom) ? (x0 + dx * ix) : (x1 - dx * ix); - for (uint32_t iz = 0; iz <= params.tiles; iz++) { - pos.z = z0 + dz * iz; - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(ix * duv, iz * duv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - } - - // left/right vertices - for (uint32_t left_right = 0; left_right < 2; left_right++) { - _sshape_vec4_t pos = _sshape_vec4((0==left_right) ? x0:x1, 0.0f, 0.0f, 1.0f); - const _sshape_vec4_t norm = _sshape_vec4((0==left_right) ? -1.0f:1.0f, 0.0f, 0.0f, 0.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - for (uint32_t iy = 0; iy <= params.tiles; iy++) { - pos.y = (0==left_right) ? (y1 - dy * iy) : (y0 + dy * iy); - for (uint32_t iz = 0; iz <= params.tiles; iz++) { - pos.z = z0 + dz * iz; - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(iy * duv, iz * duv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - } - - // front/back vertices - for (uint32_t front_back = 0; front_back < 2; front_back++) { - _sshape_vec4_t pos = _sshape_vec4(0.0f, 0.0f, (0==front_back) ? z0:z1, 1.0f); - const _sshape_vec4_t norm = _sshape_vec4(0.0f, 0.0f, (0==front_back) ? -1.0f:1.0f, 0.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - for (uint32_t ix = 0; ix <= params.tiles; ix++) { - pos.x = (0==front_back) ? (x1 - dx * ix) : (x0 + dx * ix); - for (uint32_t iy = 0; iy <= params.tiles; iy++) { - pos.y = y0 + dy * iy; - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(ix * duv, iy * duv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - } - - // build indices - const uint16_t verts_per_face = (params.tiles + 1) * (params.tiles + 1); - for (uint16_t face = 0; face < 6; face++) { - uint16_t face_start_index = start_index + face * verts_per_face; - for (uint16_t j = 0; j < params.tiles; j++) { - for (uint16_t i = 0; i < params.tiles; i++) { - const uint16_t i0 = face_start_index + (j * (params.tiles + 1)) + i; - const uint16_t i1 = i0 + 1; - const uint16_t i2 = i0 + params.tiles + 1; - const uint16_t i3 = i2 + 1; - _sshape_add_triangle(&buf, i0, i1, i3); - _sshape_add_triangle(&buf, i0, i3, i2); - } - } - } - return buf; -} - -/* - Geometry layout for spheres is as follows (for 5 slices, 4 stacks): - - + + + + + + north pole - |\ |\ |\ |\ |\ - | \| \| \| \| \ - +--+--+--+--+--+ 30 vertices (slices + 1) * (stacks + 1) - |\ |\ |\ |\ |\ | 30 triangles (2 * slices * stacks) - (2 * slices) - | \| \| \| \| \| 2 orphaned vertices - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ - \ |\ |\ |\ |\ | - \| \| \| \| \| - + + + + + + south pole -*/ -SOKOL_API_IMPL sshape_buffer_t sshape_build_sphere(const sshape_buffer_t* in_buf, const sshape_sphere_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_sphere_t params = _sshape_sphere_defaults(in_params); - const uint32_t num_vertices = _sshape_sphere_num_vertices(params.slices, params.stacks); - const uint32_t num_indices = _sshape_sphere_num_indices(params.slices, params.stacks); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - uint32_t rand_seed = 0x12345678; - const float pi = 3.14159265358979323846f; - const float two_pi = 2.0f * pi; - const float du = 1.0f / params.slices; - const float dv = 1.0f / params.stacks; - - // generate vertices - for (uint32_t stack = 0; stack <= params.stacks; stack++) { - const float stack_angle = (pi * stack) / params.stacks; - const float sin_stack = sinf(stack_angle); - const float cos_stack = cosf(stack_angle); - for (uint32_t slice = 0; slice <= params.slices; slice++) { - const float slice_angle = (two_pi * slice) / params.slices; - const float sin_slice = sinf(slice_angle); - const float cos_slice = cosf(slice_angle); - const _sshape_vec4_t norm = _sshape_vec4(-sin_slice * sin_stack, cos_stack, cos_slice * sin_stack, 0.0f); - const _sshape_vec4_t pos = _sshape_vec4(norm.x * params.radius, norm.y * params.radius, norm.z * params.radius, 1.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(1.0f - slice * du, 1.0f - stack * dv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - - // generate indices - { - // north-pole triangles - const uint16_t row_a = start_index; - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_b + slice, row_b + slice + 1); - } - } - // stack triangles - for (uint16_t stack = 1; stack < params.stacks - 1; stack++) { - const uint16_t row_a = start_index + stack * (params.slices + 1); - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_b + slice + 1, row_a + slice + 1); - _sshape_add_triangle(&buf, row_a + slice, row_b + slice, row_b + slice + 1); - } - } - { - // south-pole triangles - const uint16_t row_a = start_index + (params.stacks - 1) * (params.slices + 1); - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_b + slice + 1, row_a + slice + 1); - } - } - return buf; -} - -/* - Geometry for cylinders is as follows (2 stacks, 5 slices): - - + + + + + + - |\ |\ |\ |\ |\ - | \| \| \| \| \ - +--+--+--+--+--+ - +--+--+--+--+--+ 42 vertices (2 wasted) (slices + 1) * (stacks + 5) - |\ |\ |\ |\ |\ | 30 triangles (2 * slices * stacks) + (2 * slices) - | \| \| \| \| \| - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ - +--+--+--+--+--+ - \ |\ |\ |\ |\ | - \| \| \| \| \| - + + + + + + -*/ -static void _sshape_build_cylinder_cap_pole(sshape_buffer_t* buf, const sshape_cylinder_t* params, float pos_y, float norm_y, float du, float v, uint32_t* rand_seed) { - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms->transform, _sshape_vec4(0.0f, norm_y, 0.0f, 0.0f))); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms->transform, _sshape_vec4(0.0f, pos_y, 0.0f, 1.0f)); - for (uint32_t slice = 0; slice <= params->slices; slice++) { - const _sshape_vec2_t uv = _sshape_vec2(slice * du, 1.0f - v); - const uint32_t color = params->random_colors ? _sshape_rand_color(rand_seed) : params->color; - _sshape_add_vertex(buf, tpos, tnorm, uv, color); - } -} - -static void _sshape_build_cylinder_cap_ring(sshape_buffer_t* buf, const sshape_cylinder_t* params, float pos_y, float norm_y, float du, float v, uint32_t* rand_seed) { - const float two_pi = 2.0f * 3.14159265358979323846f; - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms->transform, _sshape_vec4(0.0f, norm_y, 0.0f, 0.0f))); - for (uint32_t slice = 0; slice <= params->slices; slice++) { - const float slice_angle = (two_pi * slice) / params->slices; - const float sin_slice = sinf(slice_angle); - const float cos_slice = cosf(slice_angle); - const _sshape_vec4_t pos = _sshape_vec4(sin_slice * params->radius, pos_y, cos_slice * params->radius, 1.0f); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms->transform, pos); - const _sshape_vec2_t uv = _sshape_vec2(slice * du, 1.0f - v); - const uint32_t color = params->random_colors ? _sshape_rand_color(rand_seed) : params->color; - _sshape_add_vertex(buf, tpos, tnorm, uv, color); - } -} - -SOKOL_SHAPE_API_DECL sshape_buffer_t sshape_build_cylinder(const sshape_buffer_t* in_buf, const sshape_cylinder_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_cylinder_t params = _sshape_cylinder_defaults(in_params); - const uint32_t num_vertices = _sshape_cylinder_num_vertices(params.slices, params.stacks); - const uint32_t num_indices = _sshape_cylinder_num_indices(params.slices, params.stacks); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - uint32_t rand_seed = 0x12345678; - const float two_pi = 2.0f * 3.14159265358979323846f; - const float du = 1.0f / params.slices; - const float dv = 1.0f / (params.stacks + 2); - const float y0 = params.height * 0.5f; - const float y1 = -params.height * 0.5f; - const float dy = params.height / params.stacks; - - // generate vertices - _sshape_build_cylinder_cap_pole(&buf, ¶ms, y0, 1.0f, du, 0.0f, &rand_seed); - _sshape_build_cylinder_cap_ring(&buf, ¶ms, y0, 1.0f, du, dv, &rand_seed); - for (uint32_t stack = 0; stack <= params.stacks; stack++) { - const float y = y0 - dy * stack; - const float v = dv * stack + dv; - for (uint32_t slice = 0; slice <= params.slices; slice++) { - const float slice_angle = (two_pi * slice) / params.slices; - const float sin_slice = sinf(slice_angle); - const float cos_slice = cosf(slice_angle); - const _sshape_vec4_t pos = _sshape_vec4(sin_slice * params.radius, y, cos_slice * params.radius, 1.0f); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec4_t norm = _sshape_vec4(sin_slice, 0.0f, cos_slice, 0.0f); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - const _sshape_vec2_t uv = _sshape_vec2(slice * du, 1.0f - v); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - _sshape_build_cylinder_cap_ring(&buf, ¶ms, y1, -1.0f, du, 1.0f - dv, &rand_seed); - _sshape_build_cylinder_cap_pole(&buf, ¶ms, y1, -1.0f, du, 1.0f, &rand_seed); - - // generate indices - { - // top-cap indices - const uint16_t row_a = start_index; - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_b + slice + 1, row_b + slice); - } - } - // shaft triangles - for (uint16_t stack = 0; stack < params.stacks; stack++) { - const uint16_t row_a = start_index + (stack + 2) * (params.slices + 1); - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_a + slice + 1, row_b + slice + 1); - _sshape_add_triangle(&buf, row_a + slice, row_b + slice + 1, row_b + slice); - } - } - { - // bottom-cap indices - const uint16_t row_a = start_index + (params.stacks + 3) * (params.slices + 1); - const uint16_t row_b = row_a + params.slices + 1; - for (uint16_t slice = 0; slice < params.slices; slice++) { - _sshape_add_triangle(&buf, row_a + slice, row_a + slice + 1, row_b + slice + 1); - } - } - return buf; -} - -/* - Geometry layout for torus (sides = 4, rings = 5): - - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ 30 vertices (sides + 1) * (rings + 1) - |\ |\ |\ |\ |\ | 40 triangles (2 * sides * rings) - | \| \| \| \| \| - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ - |\ |\ |\ |\ |\ | - | \| \| \| \| \| - +--+--+--+--+--+ -*/ -SOKOL_API_IMPL sshape_buffer_t sshape_build_torus(const sshape_buffer_t* in_buf, const sshape_torus_t* in_params) { - SOKOL_ASSERT(in_buf && in_params); - const sshape_torus_t params = _sshape_torus_defaults(in_params); - const uint32_t num_vertices = _sshape_torus_num_vertices(params.sides, params.rings); - const uint32_t num_indices = _sshape_torus_num_indices(params.sides, params.rings); - sshape_buffer_t buf = *in_buf; - if (!_sshape_validate_buffer(&buf, num_vertices, num_indices)) { - buf.valid = false; - return buf; - } - buf.valid = true; - const uint16_t start_index = _sshape_base_index(&buf); - if (!params.merge) { - _sshape_advance_offset(&buf.vertices); - _sshape_advance_offset(&buf.indices); - } - - uint32_t rand_seed = 0x12345678; - const float two_pi = 2.0f * 3.14159265358979323846f; - const float dv = 1.0f / params.sides; - const float du = 1.0f / params.rings; - - // generate vertices - for (uint32_t side = 0; side <= params.sides; side++) { - const float phi = (side * two_pi) / params.sides; - const float sin_phi = sinf(phi); - const float cos_phi = cosf(phi); - for (uint32_t ring = 0; ring <= params.rings; ring++) { - const float theta = (ring * two_pi) / params.rings; - const float sin_theta = sinf(theta); - const float cos_theta = cosf(theta); - - // torus surface position - const float spx = sin_theta * (params.radius - (params.ring_radius * cos_phi)); - const float spy = sin_phi * params.ring_radius; - const float spz = cos_theta * (params.radius - (params.ring_radius * cos_phi)); - - // torus position with ring-radius zero (for normal computation) - const float ipx = sin_theta * params.radius; - const float ipy = 0.0f; - const float ipz = cos_theta * params.radius; - - const _sshape_vec4_t pos = _sshape_vec4(spx, spy, spz, 1.0f); - const _sshape_vec4_t norm = _sshape_vec4(spx - ipx, spy - ipy, spz - ipz, 0.0f); - const _sshape_vec4_t tpos = _sshape_mat4_mul(¶ms.transform, pos); - const _sshape_vec4_t tnorm = _sshape_vec4_norm(_sshape_mat4_mul(¶ms.transform, norm)); - const _sshape_vec2_t uv = _sshape_vec2(ring * du, 1.0f - side * dv); - const uint32_t color = params.random_colors ? _sshape_rand_color(&rand_seed) : params.color; - _sshape_add_vertex(&buf, tpos, tnorm, uv, color); - } - } - - // generate indices - for (uint16_t side = 0; side < params.sides; side++) { - const uint16_t row_a = start_index + side * (params.rings + 1); - const uint16_t row_b = row_a + params.rings + 1; - for (uint16_t ring = 0; ring < params.rings; ring++) { - _sshape_add_triangle(&buf, row_a + ring, row_a + ring + 1, row_b + ring + 1); - _sshape_add_triangle(&buf, row_a + ring, row_b + ring + 1, row_b + ring); - } - } - return buf; -} - -SOKOL_API_IMPL sg_buffer_desc sshape_vertex_buffer_desc(const sshape_buffer_t* buf) { - SOKOL_ASSERT(buf && buf->valid); - sg_buffer_desc desc = { 0 }; - if (buf->valid) { - desc.type = SG_BUFFERTYPE_VERTEXBUFFER; - desc.usage = SG_USAGE_IMMUTABLE; - desc.data.ptr = buf->vertices.buffer.ptr; - desc.data.size = buf->vertices.data_size; - } - return desc; -} - -SOKOL_API_IMPL sg_buffer_desc sshape_index_buffer_desc(const sshape_buffer_t* buf) { - SOKOL_ASSERT(buf && buf->valid); - sg_buffer_desc desc = { 0 }; - if (buf->valid) { - desc.type = SG_BUFFERTYPE_INDEXBUFFER; - desc.usage = SG_USAGE_IMMUTABLE; - desc.data.ptr = buf->indices.buffer.ptr; - desc.data.size = buf->indices.data_size; - } - return desc; -} - -SOKOL_SHAPE_API_DECL sshape_element_range_t sshape_element_range(const sshape_buffer_t* buf) { - SOKOL_ASSERT(buf && buf->valid); - SOKOL_ASSERT(buf->indices.shape_offset < buf->indices.data_size); - SOKOL_ASSERT(0 == (buf->indices.shape_offset & (sizeof(uint16_t) - 1))); - SOKOL_ASSERT(0 == (buf->indices.data_size & (sizeof(uint16_t) - 1))); - sshape_element_range_t range = { 0 }; - range.base_element = (int) (buf->indices.shape_offset / sizeof(uint16_t)); - if (buf->valid) { - range.num_elements = (int) ((buf->indices.data_size - buf->indices.shape_offset) / sizeof(uint16_t)); - } - else { - range.num_elements = 0; - } - return range; -} - -SOKOL_API_IMPL sg_vertex_buffer_layout_state sshape_vertex_buffer_layout_state(void) { - sg_vertex_buffer_layout_state state = { 0 }; - state.stride = sizeof(sshape_vertex_t); - return state; -} - -SOKOL_API_IMPL sg_vertex_attr_state sshape_position_vertex_attr_state(void) { - sg_vertex_attr_state state = { 0 }; - state.offset = offsetof(sshape_vertex_t, x); - state.format = SG_VERTEXFORMAT_FLOAT3; - return state; -} - -SOKOL_API_IMPL sg_vertex_attr_state sshape_normal_vertex_attr_state(void) { - sg_vertex_attr_state state = { 0 }; - state.offset = offsetof(sshape_vertex_t, normal); - state.format = SG_VERTEXFORMAT_BYTE4N; - return state; -} - -SOKOL_API_IMPL sg_vertex_attr_state sshape_texcoord_vertex_attr_state(void) { - sg_vertex_attr_state state = { 0 }; - state.offset = offsetof(sshape_vertex_t, u); - state.format = SG_VERTEXFORMAT_USHORT2N; - return state; -} - -SOKOL_API_IMPL sg_vertex_attr_state sshape_color_vertex_attr_state(void) { - sg_vertex_attr_state state = { 0 }; - state.offset = offsetof(sshape_vertex_t, color); - state.format = SG_VERTEXFORMAT_UBYTE4N; - return state; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -#endif // SOKOL_SHAPE_IMPL diff --git a/source/thirdparty/sokol/util/sokol_spine.h b/source/thirdparty/sokol/util/sokol_spine.h deleted file mode 100644 index 7b677480..00000000 --- a/source/thirdparty/sokol/util/sokol_spine.h +++ /dev/null @@ -1,5949 +0,0 @@ -#if defined(SOKOL_IMPL) && !defined(SOKOL_SPINE_IMPL) -#define SOKOL_SPINE_IMPL -#endif -#ifndef SOKOL_SPINE_INCLUDED -/* - sokol_spine.h -- a sokol-gfx renderer for the spine-c runtime - (see https://github.com/EsotericSoftware/spine-runtimes/tree/4.1/spine-c) - - Project URL: https://github.com/floooh/sokol - - Do this: - #define SOKOL_IMPL or - #define SOKOL_SPINE_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 - - ...optionally provide the following macros to override defaults: - - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_SPINE_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_DECL - same as SOKOL_SPINE_API_DECL - SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - - If sokol_spine.h is compiled as a DLL, define the following before - including the declaration or implementation: - - SOKOL_DLL - - On Windows, SOKOL_DLL will define SOKOL_SPINE_API_DECL as __declspec(dllexport) - or __declspec(dllimport) as needed. - - Include the following headers before including sokol_spine.h: - - sokol_gfx.h - - Include the following headers before include the sokol_spine.h *IMPLEMENTATION*: - - spine/spine.h - - You'll also need to compile and link with the spine-c runtime: - - https://github.com/EsotericSoftware/spine-runtimes/tree/4.1/spine-c/spine-c - - - FEATURE OVERVIEW - ================ - sokol_spine.h is a sokol-gfx renderer and 'handle wrapper' for Spine - (http://en.esotericsoftware.com/spine-in-depth) on top of the - spine-c runtime: http://en.esotericsoftware.com/spine-c (source code: - https://github.com/EsotericSoftware/spine-runtimes/tree/4.1/spine-c/spine-c). - - The sokol-gfx renderer allows to manage multiple contexts for rendering - Spine scenes into different sokol-gfx render passes (similar to sokol-gl and - sokol-debugtext), allows to split rendering into layers to mix Spine - rendering with other rendering operations, and it automatically batches - adjacent draw calls for Spine objects that use the same texture and in the - same layer. - - Sokol-spine wraps 'raw' spine-c objects with tagged index handles. This - eliminates the risk of memory corruption via dangling pointers. Any - API calls involving invalid objects either result in a no-op, or - in a proper error. - - The sokol-spine API exposes four 'base object types', and a number of - 'subobject types' which are owned by base objects. - - Base object types are: - - - sspine_atlas: A wrapper around a spine-c spAtlas object, each spAtlas - object owns at least one spAtlasPage object, and each spAtlasPage object - owns exactly one sokol-gfx image object. - - - sspine_skeleton: A skeleton object requires an atlas object for creation, - and is a wrapper around one spine-c spSkeletonData and one - spAnimationStateData object. both contain the shared static data for - individual spine instances - - - sspine_instance: Instance objects are created from skeleton objects. - Instances are the objects that are actually getting rendered. Each instance - tracks its own transformation and animation state, but otherwise just - references shared data of the skeleton object it was created from. An - sspine_instance object is a wrapper around one spine-c spSkeleton, - spAnimationState and spSkeletonClipping object each. - - - sspine_skinset: Skin-set objects are collections of skins which define - the look of an instance. Some Spine scenes consist of combinable skins - (for instance a human character could offer different skins for different - types of clothing, hats, scarfs, shirts, pants, and so on..., and a skin - set would represent a specific outfit). - - Subobject types allow to inspect and manipulate Spine objects in more detail: - - - sspine_anim: Each skeleton object usually offers animations which can - then be scheduled and mixed on an instance. - - - sspine_bone: Bone objects are the hierarchical transform nodes of - a skeleton. The sokol-spine API allows both to inspect the shared - static bone attributes of an sspine_skeleton object, as well as - inspecting and manipulating the per-instance bone attributes - on an sspine_instance object. - - - sspine_event: A running Spine animation may fire 'events' at certain - positions in time (for instance a 'footstep' event whenever a foot - hits the ground). Events can be used to play sound effects (or visual - effects) at the right time. - - - sspine_iktarget: Allows to set the target position for a group of - bones controlled by inverse kinematics. - - There's a couple of other subobject types which are mostly useful to - inspect the interior structure of skeletons. Those will be explained - in detail further down. - - MINIMAL API USAGE OVERVIEW - ========================== - During initialization: - - - call sspine_setup() after initializing sokol-gfx - - create an atlas object from a Spine atlas file with sspine_make_atlas() - - load and initialize the sokol-gfx image objects referenced by the atlas - - create a skeleton object from a Spine skeleton file with sspine_make_skeleton() - - create at least one instance object with sspine_make_instance() - - In the frame loop, outside of sokol-gfx render passes: - - - if needed, move instances around with sspine_set_position() - - if needed, schedule new animations with sspine_set_animation() and sspine_add_animation() - - each frame, advance the current instance animation state with sspine_update_instance() - - each frame, render instances with sspine_draw_instance_in_layer(), this just records - vertices, indices and draw commands into internal buffers, but does no actual - sokol-gfx rendering - - In the frame loop, inside a sokol-gfx render pass: - - - call sspine_draw_layer() to draw all previously recorded instances in a specific layer - - On shutdown: - - - call sspine_shutdown(), ideally before shutting down sokol-gfx - - QUICKSTART STEP BY STEP - ======================= - For a simple demo program using sokol_app.h, sokol_gfx.h and sokol_fetch.h, - see here: [TODO: add link to spine-simple-sapp wasm demo]. - - - sokol_spine.h must be included after sokol_gfx.h (this is true both - for the declaration and implementation): - - #include "sokol_gfx.h" - #include "sokol_spine.h" - - - ...and sokol_gfx.h must be initialized before sokol_spine.h: - - sg_setup(&(sg_desc){ ... }); - sspine_setup(&(sspine_desc){ ... }); - - - You should always provide a logging callback to sokol-spine, otherwise - no warning or errors will be logged. The easiest way is to use sokol_log.h - for this: - - #include "sokol_log.h" - - sspine_setup(&(sspine_desc){ - .logger = { - .func = slog_func - } - }); - - - You can tweak the memory usage of sokol-spine by limiting or expanding the - maximum number of vertices, draw commands and pool sizes: - - sspine_setup(&(sspine_desc){ - .max_vertices = 1024, // default: (1<<16) = 65536 - .max_commands = 128, // default: (1<<14) = 16384 - .context_pool_size = 1, // default: 4 - .atlas_pool_size = 1, // default: 64 - .skeleton_pool_size = 1, // default: 64 - .skinset_pool_size = 1, // default: 64 - .instance_pool_size = 16, // default: 1024 - .logger = { - .func = slog_func, - } - }); - - Sokol-spine uses 32-bit vertex-indices for rendering - (SG_INDEXTYPE_UINT32), so that the maximum number of Spine vertices - in a frame isn't limited to (1<<16). - - - You can override memory allocation and logging with your own - functions, this is explained in detail further down: - - sspine_setup(&(sspine_desc){ - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ..., - }, - .logger = { - .log_func = my_log_func, - .user_data = ..., - } - }); - - - After initialization, the first thing you need is an sspine_atlas object. - Sokol-spine doesn't concern itself with file IO, it expects all external - data to be provided as pointer/size pairs: - - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){ - .data = { - .ptr = ..., // pointer to Spine atlas file data in memory - .size = ..., // atlas file data size in bytes - } - }); - assert(sspine_atlas_valid(atlas)); - - If you load the atlas data asynchronously, you can still run your - per-frame rendering code without waiting for the atlas data to be loaded - and the atlas to be created. This works because calling sokol-spine - functions with 'invalid' object handles is a valid no-op. - - - Optionally you can override some or all of the atlas texture creation parameters: - - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){ - .data = { ... }, - .overrides = { - .min_filter = SG_FILTER_NEAREST, - .mag_filter = SG_FILTER_NEAREST, - .mipmap_filter = SG_FILTER_NEAREST, - .wrap_u = SG_WRAP_MIRROR, - .wrap_v = SG_WRAP_MIRROR, - .premul_alpha_enabled = ..., - .premul_alpha_disabled = ..., - } - }); - - - The atlas file itself doesn't contain any texture data, it only contains - filenames of the required textures. Sokol-spine has already allocated - a sokol-gfx sg_image and sg_sample handle for each required texture, but the - actual loading and initialization must be performed by user code: - - // iterate over atlas textures and initialize sokol-gfx image objects - // with existing handles - const int num = sspine_num_images(atlas); - for (int i = 0; i < num; i++) { - const sspine_image img = sspine_image_by_index(atlas, i); - const sspine_image_info img_info = sspine_get_image_info(img); - assert(img_info.valid); - assert(!img_info.filename.truncated); - - // the filename is now in img_info.filename.cstr, 'somehow' - // load and decode the image data into memory, and then - // initialize the sokol-gfx image from the existing sg_image handle - // in img_info.sgimage: - sg_init_image(img_info.sgimage, &(sg_image_desc){ - .width = ..., - .height = ..., - .pixel_format = ..., - .data.subimage[0][0] = { - .ptr = ..., // pointer to decoded image pixel data - .size = ..., // size of decoded image pixel data in bytes - } - }); - - // ...and same procedure for the sampler object - sg_init_sampler(img_info.sgsampler, &(sg_image_desc){ - .min_filter = img_info.min_filter, - .mag_filter = img_info.mag_filter, - .mipmap_filter = img_info.mipmap_filter, - .wrap_u = img_info.wrap_u, - .wrap_v = img_info.wrap_v, - }); - } - - If you load the image data asynchronously, you can still simply start rendering - before the image data is loaded. This works because sokol-gfx will silently drop - any rendering operations that involve 'incomplete' objects. - - - Once an atlas object has been created (independently from loading any image data), - an sspine_skeleton object is needed next. This requires a valid atlas object - handle as input, and a pointer to the Spine skeleton file data loaded into memory. - - Spine skeleton files come in two flavours: binary or json, for binary data, - a ptr/size pair must be provided: - - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, // atlas must be a valid sspine_atlas handle - .binary_data = { - .ptr = ..., // pointer to binary skeleton data in memory - .size = ..., // size of binary skeleton data in bytes - } - }); - assert(sspine_skeleton_valid(skeleton)); - - For JSON skeleton file data, the data must be provided as a zero-terminated C string: - - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - .json_data = ..., // JSON skeleton data as zero-terminated(!) C-string - }); - - Like with all sokol-spine objects, if you load the skeleton data asynchronously - and only then create a skeleton object, you can already start rendering before - the data is loaded and the Spine objects have been created. Any operations - involving 'incomplete' handles will be dropped. - - - You can pre-scale the Spine scene size, and you can provide a default cross-fade - duration for animation mixing: - - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - .binary_data = { ... }, - .prescale = 0.5f, // scale to half-size - .anim_default_mix = 0.2f, // default anim mixing cross-fade duration 0.2 seconds - }); - - - Once the skeleton object has been created, it's finally time to create one or many instance objects. - If you want to independently render and animate the 'same' Spine object many times in a frame, - you should only create one sspine_skeleton object, and then as many sspine_instance object - as needed from the shared skeleton object: - - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){ - .skeleton = skeleton, // must be a valid skeleton handle - }); - assert(sspine_instance_valid(instance)); - - After creation, the sspine_instance will have a 'default skin' set as its appearance. - - - To set the position of an instance: - - sspine_set_position(inst, (sspine_vec2){ .x=..., .y=... }); - - Sokol-spine doesn't define a specific unit (like pixels or meters), instead the - rendering coordinate system is defined later at 'render time'. - - - To schedule an initial looping animation by its name: - - // first lookup up the animation by name on the skeleton: - sspine_anim anim = sspine_anim_by_name(skeleton, "walk"); - assert(sspine_anim_valid(anim)); - - // then schedule the animation on the instance, on mixer track 0, as looping: - sspine_set_animation(instance, anim, 0, true); - - Scheduling and mixing animations will be explained in more detail further down. - - - To advance and mix instance animations: - - sspine_update_instance(instance, delta_time_in_seconds); - - Usually you'd call this each frame for each active instance with the - frame duration in seconds. - - - Now it's finally time to 'render' the instance at its current position and - animation state: - - sspine_draw_instance_in_layer(instance, 0); - - Instances are generally rendered into numbered virtual 'render layers' (in this - case, layer 0). Layers are useful for interleaving sokol-spine rendering - with other rendering commands (like background and foreground tile maps, - sprites or text). - - - It's important to note that no actual sokol-gfx rendering happens in - sspine_draw_instance_in_layer(), instead only vertices, indices and - draw commands are recorded into internal memory buffes. - - - The only sokol-spine function which *must* (and should) be called inside - a sokol-gfx rendering pass is sspine_draw_layer(). - - This renders all draw commands that have been recorded previously in a - specific layer via sspine_draw_instance_in_layer(). - - const sspine_layer_transform tform = { ... }; - - sg_begin_default_pass(...); - sspine_draw_layer(0, tform); - sg_end_pass(); - sg_commit(); - - IMPORTANT: DO *NOT* MIX any calls to sspine_draw_instance_in_layer() - with sspine_draw_layer(), as this will confuse the internal draw command - recording. Ideally, move all sokol-gfx pass rendering (including all - sspine_draw_layer() calls) towards the end of the frame, separate from - any other sokol-spine calls. - - The sspine_layer_transform struct defines the layer's screen space coordinate - system. For instance to map Spine coordinates to framebuffer pixels, with the - origin in the screen center, you'd setup the layer transform like this: - - const float width = sapp_widthf(); - const float height = sapp_heightf(); - const sspine_layer_transform tform = { - .size = { .x = width, .y = height }, - .origin = { .x = width * 0.5f, .y = height * 0.5f }, - }; - - With this pixel mapping, the Spine scene would *not* scale with window size, - which often is not very useful. Instead it might make more sense to render - to a fixed 'virtual' resolution, for instance 1024 * 768: - - const sspine_layer_transform tform = { - .size = { .x = 1024.0f, .y = 768.0f }, - .origin = { .x = 512.0f, .y = 384.0f }, - }; - - How to configure a virtual resolution with a fixed aspect ratio is - left as an exercise to the reader ;) - - - That's it for basic sokol-spine setup and rendering. Any existing objects - will automatically be cleaned up when calling sspine_shutdown(), this - should be called before shutting down sokol-gfx, but this is not required: - - sspine_shutdown(); - sg_shutdown(); - - - You can explicitly destroy the base object types if you don't need them - any longer. This will cause the underlying spine-c objects to be - freed and the memory to be returned to the operating system: - - sspine_destroy_instance(instance); - sspine_destroy_skinset(skinset); - sspine_destroy_skeleton(skeleton); - sspine_destroy_atlas(atlas); - - You can destroy these objects in any order without causing memory corruption - issues. Instead any dependent object handles will simply become invalid (e.g. - if you destroy an atlas object, all skeletons and instances created from - this atlas will 'technically' still exist, but their handles will resolve to - 'invalid' and all sokol-spine calls involving these handles will silently fail). - - For instance: - - // create an atlas, skeleton and instance - sspine_atlas atlas = sspine_make_atlas(&(sspine_atlas_desc){ ... }); - assert(sspine_atlas_valid(atlas)); - - sspine_skeleton skeleton = sspine_make_skeleton(&(sspine_skeleton_desc){ - .atlas = atlas, - ... - }); - assert(sspine_skeleton_valid(skeleton)); - - sspine_instance instance = sspine_make_instance(&(sspine_instance_desc){ - .skeleton = skeleton, - }); - assert(sspine_instance_valid(instance)); - - // destroy the atlas object: - sspine_destroy_atlas(atlas); - - // the skeleton and instance handle should now be invalid, but - // otherwise, nothing bad will happen: - if (!sspine_skeleton_valid(skeleton)) { - ... - } - if (!sspine_instance_valid(instance)) { - ... - } - - RENDERER DETAILS - ================ - Any rendering related work happens in the functions sspine_draw_instance_in_layer() and - sspine_draw_layer(). - - sspine_draw_instance_in_layer() will result in vertices, indices and internal - draw commands which will be recorded into internal memory buffers (e.g. - no sokol-gfx functions will be called here). - - If possible, batching will be performed by merging a new draw command with - the previously recorded draw command. For two draw commands to be merged, - the following conditions must be tru: - - - rendering needs to go into the same layer - - the same atlas texture must be used - - the blend mode must be compatible (the Spine blending modes - 'normal' and 'additive' can be merged, but not 'multiply') - - the same premultiplied alpha mode must be used - - To make the most out of batching: - - - use Spine objects which only have a single atlas texture - and blend mode across all slots - - group sspine_draw_instance_in_layer() calls by layer - - After all instances have been 'rendered' (or rather: recorded) into layers, - the actually rendering happens inside a sokol-gfx pass by calling the - function sspine_draw_layer() for each layer in 'z order' (e.g. the layer - index doesn't matter for z-ordering, only the order how sspine_draw_layer() is - called). - - Only the first call to sspine_draw_layer() in a frame will copy the recorded - vertices and indices into sokol-gfx buffers. - - Each call to sspine_draw_layer() will iterate over all recorded (and - hopefully well-batched) draw commands, skip any draw commands with a - non-matching layer index, and draw only those with a matching layer by - calling: - - - if the pipeline object has changed: - - sg_apply_pipeline() - - sg_apply_uniforms() for the vertex stage - - if the atlas texture has changed: - - sg_apply_bindings() - - if the premultiplied-alpha mode has changed: - - sg_apply_uniforms() for the fragment stage - - and finally sg_draw() - - The main purpose of render layers is to mix Spine rendering with other - render operations. In the not too distant future, the same render layer idea - will also be implemented at least for sokol-gl and sokol-debugtext. - - FIXME: does this section need more details about layer transforms? - - RENDERING WITH CONTEXTS - ======================= - At first glance, render contexts may look like more heavy-weight - render layers, but they serve a different purpose: they are useful - if Spine rendering needs to happen in different sokol-gfx render passes - with different pixel formats and MSAA sample counts. - - All Spine rendering happens within a context, even you don't call any - of the context API functions, in this case, an internal 'default context' - will be used. - - Each context has its own internal vertex-, index- and command buffer and - all context state is completely independent from any other contexts. - - To create a new context object, call: - - sspine_context ctx = sspine_make_context(&(sspine_context_desc){ - .max_vertices = ..., - .max_commands = ..., - .color_format = SG_PIXELFORMAT_..., - .depth_format = SG_PIXELFORMAT_..., - .sample_count = ..., - .color_write_mask = SG_COLORMASK_..., - }); - - The color_format, depth_format and sample_count items must be compatible - with the sokol-gfx render pass you're going to render into. - - If you omit the color_format, depth_format and sample_count designators, - the new context will be compatible with the sokol-gfx default pass - (which is most likely not what you want, unless your offscreen render passes - exactly match the default pass attributes). - - Once a context has been created, it can be made active with: - - sspine_set_context(ctx); - - To set the default context again: - - sspine_set_contxt(sspine_default_context()); - - ...and to get the currently active context: - - sspine_context cur_ctx = sspine_get_context(); - - The currently active context only matter for two functions: - - - sspine_draw_instance_in_layer() - - sspine_draw_layer() - - Alternatively you can bypass the currently set context with these - alternative functions: - - - sspine_context_draw_layer_in_instance(ctx, ...) - - sspine_context_draw_layer(ctx, ...) - - These explicitly take a context argument, completely ignore - and don't change the active context. - - You can query some information about a context with the function: - - sspine_context_info info = ssgpine_get_context_info(ctx); - - This returns the current number of recorded vertices, indices - and draw commands. - - RESOURCE STATES: - ================ - Similar to sokol-gfx, you can query the current 'resource state' of Spine - objects: - - sspine_resource_state sspine_get_atlas_resource_state(sspine_atlas atlas); - sspine_resource_state sspine_get_skeleton_resource_state(sspine_atlas atlas); - sspine_resource_state sspine_get_instance_resource_state(sspine_atlas atlas); - sspine_resource_state sspine_get_skinset_resource_state(sspine_atlas atlas); - sspine_resource_state sspine_get_context_resource_state(sspine_atlas atlas); - - This returns one of - - - SSPINE_RESOURCE_VALID: the object is valid and ready to use - - SSPINE_RESOURCE_FAILED: the object creation has failed - - SSPINE_RESOURCE_INVALID: the object or one of its dependencies is - invalid, it either no longer exists, or the handle hasn't been - initialized with a call to one of the object creation functions - - MISC HELPER FUNCTIONS: - ====================== - There's a couple of helper functions which don't fit into a big enough category - of their own: - - You can ask a skeleton for the atlas it has been created from: - - sspine_atlas atlas = sspine_get_skeleton_atlas(skeleton); - - ...and likewise, ask an instance for the skeleton it has been created from: - - sspine_skeleton skeleton = sspine_get_instance_skeleton(instance); - - ...and finally you can convert a layer transform struct into a 4x4 projection - matrix that's memory-layout compatible with sokol-gl: - - const sspine_layer_transform tform = { ... }; - const sspine_mat4 proj = sspine_layer_transform_to_mat4(&tform); - sgl_matrix_mode_projection(); - sgl_load_matrix(proj.m); - - ANIMATIONS - ========== - Animations have their own handle type sspine_anim. A valid sspine_anim - handle is either obtained by looking up an animation by name from a skeleton: - - sspine_anim anim = sspine_anim_by_name(skeleton, "walk"); - - ...or by index: - - sspine_anim anim = sspine_anim_by_index(skeleton, 0); - - The returned anim handle will be invalid if an animation of that name doesn't - exist, or the provided index is out-of-range: - - if (!sspine_anim_is_valid(anim)) { - // animation handle is not valid - } - - An animation handle will also become invalid when the skeleton object it was - created is destroyed, or otherwise becomes invalid. - - You can iterate over all animations in a skeleton: - - const int num_anims = sspine_num_anims(skeleton); - for (int anim_index = 0; anim_index < num_anims; anim_index++) { - sspine_anim anim = sspine_anim_by_index(skeleton, anim_index); - ... - } - - Since sspine_anim is a 'fat handle' (it houses a skeleton handle and an index), - there's a helper function which checks if two anim handles are equal: - - if (sspine_anim_equal(anim0, anim1)) { - ... - } - - To query information about an animation: - - const sspine_anim_info info = sspine_get_anim_info(anim); - if (info.valid) { - printf("index: %d, duration: %f, name: %s", info.index, info.duration, info.name.cstr); - } - - Scheduling and mixing animations is controlled through the following functions: - - void sspine_clear_animation_tracks(sspine_instance instance); - void sspine_clear_animation_track(sspine_instance instance, int track_index); - void sspine_set_animation(sspine_instance instance, sspine_anim anim, int track_index, bool loop); - void sspine_add_animation(sspine_instance instance, sspine_anim anim, int track_index, bool loop, float delay); - void sspine_set_empty_animation(sspine_instance instance, int track_index, float mix_duration); - void sspine_add_empty_animation(sspine_instance instance, int track_index, float mix_duration, float delay); - - Please refer to the spine-c documentation to get an idea what these functions do: - - http://en.esotericsoftware.com/spine-c#Applying-animations - - EVENTS - ====== - For a general idea of Spine events, see here: http://esotericsoftware.com/spine-events - - After calling sspine_update_instance() to advance the currently configured animations, - you can poll for triggered events like this: - - const int num_triggered_events = sspine_num_triggered_events(instance); - for (int i = 0; i < num_triggered_events; i++) { - const sspine_triggered_event_info info = sspine_get_triggered_event_info(instance, i); - if (info.valid) { - ... - } - } - - The returned sspine_triggered_event_info struct gives you the current runtime properties - of the event (in case the event has keyed properties). For the actual list of event - properties please see the actual sspine_triggered_event_info struct declaration. - - It's also possible to inspect the static event definition on a skeleton, this works - the same as iterating through animations. You can lookup an event by name, - get the number of events, lookup an event by its index, and get detailed - information about an event: - - int sspine_num_events(sspine_skeleton skeleton); - sspine_event sspine_event_by_name(sspine_skeleton skeleton, const char* name); - sspine_event sspine_event_by_index(sspine_skeleton skeleton, int index); - bool sspine_event_valid(sspine_event event); - bool sspine_event_equal(sspine_event first, sspine_event second); - sspine_event_info sspine_get_event_info(sspine_event event); - - (FIXME: shouldn't the event info struct contains an sspine_anim handle?) - - IK TARGETS - ========== - The IK target function group allows to iterate over the IK targets that have been - defined on a skeleton, find an IK target by name, get detailed information about - an IK target, and most importantly, set the world space position of an IK target - which updates the position of all bones influenced by the IK target: - - int sspine_num_iktargets(sspine_skeleton skeleton); - sspine_iktarget sspine_iktarget_by_name(sspine_skeleton skeleton, const char* name); - sspine_iktarget sspine_iktarget_by_index(sspine_skeleton skeleton, int index); - bool sspine_iktarget_valid(sspine_iktarget iktarget); - bool sspine_iktarget_equal(sspine_iktarget first, sspine_iktarget second); - sspine_iktarget_info sspine_get_iktarget_info(sspine_iktarget iktarget); - void sspine_set_iktarget_world_pos(sspine_instance instance, sspine_iktarget iktarget, sspine_vec2 world_pos); - - BONES - ===== - Skeleton bones are wrapped with an sspine_bone handle which can be created from - a skeleton handle, and either a bone name: - - sspine_bone bone = sspine_bone_by_name(skeleton, "root"); - assert(sspine_bone_valid(bone)); - - ...or a bone index: - - sspine_bone bone = sspine_bone_by_index(skeleton, 0); - assert(sspine_bone_valid(bone)); - - ...to iterate over all bones of a skeleton and query information about each - bone: - - const int num_bones = sspine_num_bones(skeleton); - for (int bone_index = 0; bone_index < num_bones; bone_index++) { - sspine_bone bone = sspine_bone_by_index(skeleton, bone_index); - const sspine_bone_info info = sspine_get_bone_info(skeleton, bone); - if (info.valid) { - ... - } - } - - The sspine_bone_info struct provides the shared, static bone state in the skeleton (like - the name, a parent bone handle, bone length, pose transform and a color attribute), - but doesn't contain any dynamic information of per-instance bones. - - To manipulate the per-instance bone attributes use the following setter functions: - - void sspine_set_bone_transform(sspine_instance instance, sspine_bone bone, const sspine_bone_transform* transform); - void sspine_set_bone_position(sspine_instance instance, sspine_bone bone, sspine_vec2 position); - void sspine_set_bone_rotation(sspine_instance instance, sspine_bone bone, float rotation); - void sspine_set_bone_scale(sspine_instance instance, sspine_bone bone, sspine_vec2 scale); - void sspine_set_bone_shear(sspine_instance instance, sspine_bone bone, sspine_vec2 shear); - - ...and to query the per-instance bone attributes, the following getters: - - sspine_bone_transform sspine_get_bone_transform(sspine_instance instance, sspine_bone bone); - sspine_vec2 sspine_get_bone_position(sspine_instance instance, sspine_bone bone); - float sspine_get_bone_rotation(sspine_instance instance, sspine_bone bone); - sspine_vec2 sspine_get_bone_scale(sspine_instance instance, sspine_bone bone); - sspine_vec2 sspine_get_bone_shear(sspine_instance instance, sspine_bone bone); - - These functions all work in the local bone coordinate system (relative to a bone's parent bone). - - To transform positions between bone-local and global space use the following helper functions: - - sspine_vec2 sspine_bone_local_to_world(sspine_instance instance, sspine_bone bone, sspine_vec2 local_pos); - sspine_vec2 sspine_bone_world_to_local(sspine_instance instance, sspine_bone bone, sspine_vec2 world_pos); - - ...and as a convenience, there's a helper function which obtains the bone position in global space - directly: - - sspine_vec2 sspine_get_bone_world_position(sspine_instance instance, sspine_bone bone); - - SKINS AND SKINSETS - ================== - Skins are named pieces of geometry which can be turned on and off, what makes Spine skins a bit - confusing is that they are hierarchical. A skin can itself be a collection of other skins. Setting - the 'root skin' will also make all 'child skins' visible. In sokol-spine collections of skins are - managed through dedicated 'skin set' objects. Under the hood they create a 'root skin' where the - skins of the skin set are attached to, but from the outside it just looks like a 'flat' collection - of skins without the tricky hierarchical management. - - Like other 'subobjects', skin handles can be obtained by the skin name from a skeleton handle: - - sspine_skin skin = sspine_skin_by_name(skeleton, "jacket"); - assert(sspine_skin_valid(skin)); - - ...or by a skin index: - - sspine_skin skin = sspine_skin_by_index(skeleton, 0); - assert(sspine_skin_valid(skin)); - - ...you can iterate over all skins of a skeleton and query some information about the skin: - - const int num_skins = sspine_num_skins(skeleton); - for (int skin_index = 0; skin_index < num_skins; skin_index++) { - sspine_skin skin = sspine_skin_by_index(skin_index); - sspine_skin_info info = sspine_get_skin_info(skin); - if (info.valid) { - ... - } - } - - Currently, the only useful query item is the skin name though. - - To make a skin visible on an instance, just call: - - sspine_set_skin(instance, skin); - - ...this will first deactivate the previous skin before setting a new skin. - - A more powerful way to configure the skin visibility is through 'skin sets'. Skin - sets are simply flat collections of skins which should be made visible at once. - A new skin set is created like this: - - sspine_skinset skinset = sspine_make_skinset(&(sspine_skinset_desc){ - .skeleton = skeleton, - .skins = { - sspine_skin_by_name(skeleton, "blue-jacket"), - sspine_skin_by_name(skeleton, "green-pants"), - sspine_skin_by_name(skeleton, "blonde-hair"), - ... - } - }); - assert(sspine_skinset_valid(skinset)) - - ...then simply set the skinset on an instance to reconfigure the appearance - of the instance: - - sspine_set_skinset(instance, skinset); - - The functions sspine_set_skinset() and sspine_set_skin() will cancel each other. - Calling sspine_set_skinset() deactivates the effect of sspine_set_skin() and - vice versa. - - - 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" - - sspine_setup(&(sspine_desc){ .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. 'sspine' - uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info - uint32_t log_item_id, // SSPINE_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_spine.h - const char* filename_or_null, // source filename, may be nullptr in release mode - void* user_data) - { - ... - } - - ...and then setup sokol-spine like this: - - sspine_setup(&(sspine_desc){ - .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. - - - 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); - } - - ... - sspine_setup(&(sspine_desc){ - // ... - .allocator = { - .alloc_fn = my_alloc, - .free_fn = my_free, - .user_data = ...; - } - }); - ... - - If no overrides are provided, malloc and free will be used. - - This only affects memory allocation calls done by sokol_gfx.h - itself though, not any allocations in OS libraries. - - - LICENSE - ======= - zlib/libpng license - - Copyright (c) 2022 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. -*/ -#define SOKOL_SPINE_INCLUDED (1) -#include -#include -#include // size_t - -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before sokol_spine.h" -#endif - -#if defined(SOKOL_API_DECL) && !defined(SOKOL_SPINE_API_DECL) -#define SOKOL_SPINE_API_DECL SOKOL_API_DECL -#endif -#ifndef SOKOL_SPINE_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_SPINE_IMPL) -#define SOKOL_SPINE_API_DECL __declspec(dllexport) -#elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_SPINE_API_DECL __declspec(dllimport) -#else -#define SOKOL_SPINE_API_DECL extern -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - SSPINE_INVALID_ID = 0, - SSPINE_MAX_SKINSET_SKINS = 32, - SSPINE_MAX_STRING_SIZE = 61, // see sspine_string struct -}; - -typedef struct sspine_context { uint32_t id; } sspine_context; -typedef struct sspine_atlas { uint32_t id; } sspine_atlas; -typedef struct sspine_skeleton { uint32_t id; } sspine_skeleton; -typedef struct sspine_instance { uint32_t id; } sspine_instance; -typedef struct sspine_skinset { uint32_t id; } sspine_skinset; - -typedef struct sspine_image { uint32_t atlas_id; int index; } sspine_image; -typedef struct sspine_atlas_page { uint32_t atlas_id; int index; } sspine_atlas_page; -typedef struct sspine_anim { uint32_t skeleton_id; int index; } sspine_anim; -typedef struct sspine_bone { uint32_t skeleton_id; int index; } sspine_bone; -typedef struct sspine_slot { uint32_t skeleton_id; int index; } sspine_slot; -typedef struct sspine_event { uint32_t skeleton_id; int index; } sspine_event; -typedef struct sspine_iktarget { uint32_t skeleton_id; int index; } sspine_iktarget; -typedef struct sspine_skin { uint32_t skeleton_id; int index; } sspine_skin; - -typedef struct sspine_range { const void* ptr; size_t size; } sspine_range; -typedef struct sspine_vec2 { float x, y; } sspine_vec2; -typedef struct sspine_mat4 { float m[16]; } sspine_mat4; -typedef sg_color sspine_color; - -typedef struct sspine_string { - bool valid; - bool truncated; - uint8_t len; - char cstr[SSPINE_MAX_STRING_SIZE]; -} sspine_string; - -typedef enum sspine_resource_state { - SSPINE_RESOURCESTATE_INITIAL, - SSPINE_RESOURCESTATE_ALLOC, - SSPINE_RESOURCESTATE_VALID, - SSPINE_RESOURCESTATE_FAILED, - SSPINE_RESOURCESTATE_INVALID, - _SSPINE_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF -} sspine_resource_state; - -// log item codes via x-macro magic -#define _SSPINE_LOG_ITEMS \ - _SSPINE_LOGITEM_XMACRO(OK, "Ok")\ - _SSPINE_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed")\ - _SSPINE_LOGITEM_XMACRO(CONTEXT_POOL_EXHAUSTED, "context pool exhausted (adjust via sspine_desc.context_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(ATLAS_POOL_EXHAUSTED, "atlas pool exhausted (adjust via sspine_desc.atlas_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(SKELETON_POOL_EXHAUSTED, "skeleton pool exhausted (adjust via sspine_desc.skeleton_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(SKINSET_POOL_EXHAUSTED, "skinset pool exhausted (adjust via sspine_desc.skinset_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(INSTANCE_POOL_EXHAUSTED, "instance pool exhausted (adjust via sspine_desc.instance_pool_size)")\ - _SSPINE_LOGITEM_XMACRO(CANNOT_DESTROY_DEFAULT_CONTEXT, "cannot destroy default context")\ - _SSPINE_LOGITEM_XMACRO(ATLAS_DESC_NO_DATA, "no data provided in sspine_atlas_desc.data")\ - _SSPINE_LOGITEM_XMACRO(SPINE_ATLAS_CREATION_FAILED, "spAtlas_create() failed")\ - _SSPINE_LOGITEM_XMACRO(SG_ALLOC_IMAGE_FAILED, "sg_alloc_image() failed")\ - _SSPINE_LOGITEM_XMACRO(SG_ALLOC_SAMPLER_FAILED, "sg_alloc_sampler() failed")\ - _SSPINE_LOGITEM_XMACRO(SKELETON_DESC_NO_DATA, "no data provided in sspine_skeleton_desc.json_data or .binary_data")\ - _SSPINE_LOGITEM_XMACRO(SKELETON_DESC_NO_ATLAS, "no atlas object provided in sspine_skeleton_desc.atlas")\ - _SSPINE_LOGITEM_XMACRO(SKELETON_ATLAS_NOT_VALID, "sspine_skeleton_desc.atlas is not in valid state")\ - _SSPINE_LOGITEM_XMACRO(CREATE_SKELETON_DATA_FROM_JSON_FAILED, "spSkeletonJson_readSkeletonData() failed")\ - _SSPINE_LOGITEM_XMACRO(CREATE_SKELETON_DATA_FROM_BINARY_FAILED, "spSkeletonBinary_readSkeletonData() failed")\ - _SSPINE_LOGITEM_XMACRO(SKINSET_DESC_NO_SKELETON, "no skeleton object provided in sspine_skinset_desc.skeleton")\ - _SSPINE_LOGITEM_XMACRO(SKINSET_SKELETON_NOT_VALID, "sspine_skinset_desc.skeleton is not in valid state")\ - _SSPINE_LOGITEM_XMACRO(SKINSET_INVALID_SKIN_HANDLE, "invalid skin handle in sspine_skinset_desc.skins[]")\ - _SSPINE_LOGITEM_XMACRO(INSTANCE_DESC_NO_SKELETON, "no skeleton object provided in sspine_instance_desc.skeleton")\ - _SSPINE_LOGITEM_XMACRO(INSTANCE_SKELETON_NOT_VALID, "sspine_instance_desc.skeleton is not in valid state")\ - _SSPINE_LOGITEM_XMACRO(INSTANCE_ATLAS_NOT_VALID, "skeleton's atlas object no longer valid via sspine_instance_desc.skeleton")\ - _SSPINE_LOGITEM_XMACRO(SPINE_SKELETON_CREATION_FAILED, "spSkeleton_create() failed")\ - _SSPINE_LOGITEM_XMACRO(SPINE_ANIMATIONSTATE_CREATION_FAILED, "spAnimationState_create() failed")\ - _SSPINE_LOGITEM_XMACRO(SPINE_SKELETONCLIPPING_CREATION_FAILED, "spSkeletonClipping_create() failed")\ - _SSPINE_LOGITEM_XMACRO(COMMAND_BUFFER_FULL, "command buffer full (adjust via sspine_desc.max_commands)")\ - _SSPINE_LOGITEM_XMACRO(VERTEX_BUFFER_FULL, "vertex buffer (adjust via sspine_desc.max_vertices)")\ - _SSPINE_LOGITEM_XMACRO(INDEX_BUFFER_FULL, "index buffer full (adjust via sspine_desc.max_vertices)")\ - _SSPINE_LOGITEM_XMACRO(STRING_TRUNCATED, "a string has been truncated")\ - _SSPINE_LOGITEM_XMACRO(ADD_COMMIT_LISTENER_FAILED, "sg_add_commit_listener() failed")\ - -#define _SSPINE_LOGITEM_XMACRO(item,msg) SSPINE_LOGITEM_##item, -typedef enum sspine_log_item { - _SSPINE_LOG_ITEMS -} sspine_log_item; -#undef _SSPINE_LOGITEM_XMACRO - -typedef struct sspine_layer_transform { - sspine_vec2 size; - sspine_vec2 origin; -} sspine_layer_transform; - -typedef struct sspine_bone_transform { - sspine_vec2 position; - float rotation; // in degrees - sspine_vec2 scale; - sspine_vec2 shear; // in degrees -} sspine_bone_transform; - -typedef struct sspine_context_desc { - int max_vertices; - int max_commands; - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - sg_color_mask color_write_mask; -} sspine_context_desc; - -typedef struct sspine_context_info { - int num_vertices; // current number of vertices - int num_indices; // current number of indices - int num_commands; // current number of commands -} sspine_context_info; - -typedef struct sspine_image_info { - bool valid; - sg_image sgimage; - sg_sampler sgsampler; - sg_filter min_filter; - sg_filter mag_filter; - sg_filter mipmap_filter; - sg_wrap wrap_u; - sg_wrap wrap_v; - int width; - int height; - bool premul_alpha; - sspine_string filename; -} sspine_image_info; - -typedef struct sspine_atlas_overrides { - sg_filter min_filter; - sg_filter mag_filter; - sg_filter mipmap_filter; - sg_wrap wrap_u; - sg_wrap wrap_v; - bool premul_alpha_enabled; - bool premul_alpha_disabled; -} sspine_atlas_overrides; - -typedef struct sspine_atlas_desc { - sspine_range data; - sspine_atlas_overrides override; -} sspine_atlas_desc; - -typedef struct sspine_atlas_page_info { - bool valid; - sspine_atlas atlas; - sspine_image_info image; - sspine_atlas_overrides overrides; -} sspine_atlas_page_info; - -typedef struct sspine_skeleton_desc { - sspine_atlas atlas; - float prescale; - float anim_default_mix; - const char* json_data; - sspine_range binary_data; -} sspine_skeleton_desc; - -typedef struct sspine_skinset_desc { - sspine_skeleton skeleton; - sspine_skin skins[SSPINE_MAX_SKINSET_SKINS]; -} sspine_skinset_desc; - -typedef struct sspine_anim_info { - bool valid; - int index; - float duration; - sspine_string name; -} sspine_anim_info; - -typedef struct sspine_bone_info { - bool valid; - int index; - sspine_bone parent_bone; - float length; - sspine_bone_transform pose; - sspine_color color; - sspine_string name; -} sspine_bone_info; - -typedef struct sspine_slot_info { - bool valid; - int index; - sspine_bone bone; - sspine_color color; - sspine_string attachment_name; - sspine_string name; -} sspine_slot_info; - -typedef struct sspine_iktarget_info { - bool valid; - int index; - sspine_bone target_bone; - sspine_string name; -} sspine_iktarget_info; - -typedef struct sspine_skin_info { - bool valid; - int index; - sspine_string name; -} sspine_skin_info; - -typedef struct sspine_event_info { - bool valid; - int index; - int int_value; - float float_value; - float volume; - float balance; - sspine_string name; - sspine_string string_value; - sspine_string audio_path; -} sspine_event_info; - -typedef struct sspine_triggered_event_info { - bool valid; - sspine_event event; - float time; - int int_value; - float float_value; - float volume; - float balance; - sspine_string string_value; -} sspine_triggered_event_info; - -typedef struct sspine_instance_desc { - sspine_skeleton skeleton; -} sspine_instance_desc; - -typedef struct sspine_allocator { - void* (*alloc_fn)(size_t size, void* user_data); - void (*free_fn)(void* ptr, void* user_data); - void* user_data; -} sspine_allocator; - -typedef struct sspine_logger { - void (*func)( - const char* tag, // always "sspine" - uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info - uint32_t log_item_id, // SSPINE_LOGITEM_* - const char* message_or_null, // a message string, may be nullptr in release mode - uint32_t line_nr, // line number in sokol_spine.h - const char* filename_or_null, // the source filename, may be nullptr in release mode - void* user_data); - void* user_data; -} sspine_logger; - -typedef struct sspine_desc { - int max_vertices; - int max_commands; - int context_pool_size; - int atlas_pool_size; - int skeleton_pool_size; - int skinset_pool_size; - int instance_pool_size; - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - sg_color_mask color_write_mask; - sspine_allocator allocator; // optional allocation override functions (default: malloc/free) - sspine_logger logger; // optional logging function (default: NO LOGGING!) -} sspine_desc; - -// setup/shutdown -SOKOL_SPINE_API_DECL void sspine_setup(const sspine_desc* desc); -SOKOL_SPINE_API_DECL void sspine_shutdown(void); - -// context functions -SOKOL_SPINE_API_DECL sspine_context sspine_make_context(const sspine_context_desc* desc); -SOKOL_SPINE_API_DECL void sspine_destroy_context(sspine_context ctx); -SOKOL_SPINE_API_DECL void sspine_set_context(sspine_context ctx); -SOKOL_SPINE_API_DECL sspine_context sspine_get_context(void); -SOKOL_SPINE_API_DECL sspine_context sspine_default_context(void); -SOKOL_SPINE_API_DECL sspine_context_info sspine_get_context_info(sspine_context ctx); - -// create and destroy spine objects -SOKOL_SPINE_API_DECL sspine_atlas sspine_make_atlas(const sspine_atlas_desc* desc); -SOKOL_SPINE_API_DECL sspine_skeleton sspine_make_skeleton(const sspine_skeleton_desc* desc); -SOKOL_SPINE_API_DECL sspine_skinset sspine_make_skinset(const sspine_skinset_desc* desc); -SOKOL_SPINE_API_DECL sspine_instance sspine_make_instance(const sspine_instance_desc* desc); -SOKOL_SPINE_API_DECL void sspine_destroy_atlas(sspine_atlas atlas); -SOKOL_SPINE_API_DECL void sspine_destroy_skeleton(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL void sspine_destroy_skinset(sspine_skinset skinset); -SOKOL_SPINE_API_DECL void sspine_destroy_instance(sspine_instance instance); - -// configure instance appearance via skinsets -SOKOL_SPINE_API_DECL void sspine_set_skinset(sspine_instance instance, sspine_skinset skinset); - -// update instance animations before drawing -SOKOL_SPINE_API_DECL void sspine_update_instance(sspine_instance instance, float delta_time); - -// iterate over triggered events after updating an instance -SOKOL_SPINE_API_DECL int sspine_num_triggered_events(sspine_instance instance); -SOKOL_SPINE_API_DECL sspine_triggered_event_info sspine_get_triggered_event_info(sspine_instance instance, int triggered_event_index); - -// draw instance into current or explicit context -SOKOL_SPINE_API_DECL void sspine_draw_instance_in_layer(sspine_instance instance, int layer); -SOKOL_SPINE_API_DECL void sspine_context_draw_instance_in_layer(sspine_context ctx, sspine_instance instance, int layer); - -// helper function to convert sspine_layer_transform into projection matrix -SOKOL_SPINE_API_DECL sspine_mat4 sspine_layer_transform_to_mat4(const sspine_layer_transform* tform); - -// draw a layer in current context or explicit context (call once per context and frame in sokol-gfx pass) -SOKOL_SPINE_API_DECL void sspine_draw_layer(int layer, const sspine_layer_transform* tform); -SOKOL_SPINE_API_DECL void sspine_context_draw_layer(sspine_context ctx, int layer, const sspine_layer_transform* tform); - -// get current resource state (INITIAL, ALLOC, VALID, FAILED, INVALID) -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_context_resource_state(sspine_context context); -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_atlas_resource_state(sspine_atlas atlas); -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_skeleton_resource_state(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_skinset_resource_state(sspine_skinset skinset); -SOKOL_SPINE_API_DECL sspine_resource_state sspine_get_instance_resource_state(sspine_instance instance); - -// shortcut for sspine_get_*_state() == SSPINE_RESOURCESTATE_VALID -SOKOL_SPINE_API_DECL bool sspine_context_valid(sspine_context context); -SOKOL_SPINE_API_DECL bool sspine_atlas_valid(sspine_atlas atlas); -SOKOL_SPINE_API_DECL bool sspine_skeleton_valid(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL bool sspine_instance_valid(sspine_instance instance); -SOKOL_SPINE_API_DECL bool sspine_skinset_valid(sspine_skinset skinset); - -// get dependency objects -SOKOL_SPINE_API_DECL sspine_atlas sspine_get_skeleton_atlas(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_skeleton sspine_get_instance_skeleton(sspine_instance instance); - -// atlas images -SOKOL_SPINE_API_DECL int sspine_num_images(sspine_atlas atlas); -SOKOL_SPINE_API_DECL sspine_image sspine_image_by_index(sspine_atlas atlas, int index); -SOKOL_SPINE_API_DECL bool sspine_image_valid(sspine_image image); -SOKOL_SPINE_API_DECL bool sspine_image_equal(sspine_image first, sspine_image second); -SOKOL_SPINE_API_DECL sspine_image_info sspine_get_image_info(sspine_image image); - -// atlas page functions -SOKOL_SPINE_API_DECL int sspine_num_atlas_pages(sspine_atlas atlas); -SOKOL_SPINE_API_DECL sspine_atlas_page sspine_atlas_page_by_index(sspine_atlas atlas, int index); -SOKOL_SPINE_API_DECL bool sspine_atlas_page_valid(sspine_atlas_page page); -SOKOL_SPINE_API_DECL bool sspine_atlas_page_equal(sspine_atlas_page first, sspine_atlas_page second); -SOKOL_SPINE_API_DECL sspine_atlas_page_info sspine_get_atlas_page_info(sspine_atlas_page page); - -// instance transform functions -SOKOL_SPINE_API_DECL void sspine_set_position(sspine_instance instance, sspine_vec2 position); -SOKOL_SPINE_API_DECL void sspine_set_scale(sspine_instance instance, sspine_vec2 scale); -SOKOL_SPINE_API_DECL void sspine_set_color(sspine_instance instance, sspine_color color); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_position(sspine_instance instance); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_scale(sspine_instance instance); -SOKOL_SPINE_API_DECL sspine_color sspine_get_color(sspine_instance instance); - -// instance animation functions -SOKOL_SPINE_API_DECL int sspine_num_anims(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_anim sspine_anim_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_anim sspine_anim_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_anim_valid(sspine_anim anim); -SOKOL_SPINE_API_DECL bool sspine_anim_equal(sspine_anim first, sspine_anim second); -SOKOL_SPINE_API_DECL sspine_anim_info sspine_get_anim_info(sspine_anim anim); -SOKOL_SPINE_API_DECL void sspine_clear_animation_tracks(sspine_instance instance); -SOKOL_SPINE_API_DECL void sspine_clear_animation_track(sspine_instance instance, int track_index); -SOKOL_SPINE_API_DECL void sspine_set_animation(sspine_instance instance, sspine_anim anim, int track_index, bool loop); -SOKOL_SPINE_API_DECL void sspine_add_animation(sspine_instance instance, sspine_anim anim, int track_index, bool loop, float delay); -SOKOL_SPINE_API_DECL void sspine_set_empty_animation(sspine_instance instance, int track_index, float mix_duration); -SOKOL_SPINE_API_DECL void sspine_add_empty_animation(sspine_instance instance, int track_index, float mix_duration, float delay); - -// bone functions -SOKOL_SPINE_API_DECL int sspine_num_bones(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_bone sspine_bone_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_bone sspine_bone_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_bone_valid(sspine_bone bone); -SOKOL_SPINE_API_DECL bool sspine_bone_equal(sspine_bone first, sspine_bone second); -SOKOL_SPINE_API_DECL sspine_bone_info sspine_get_bone_info(sspine_bone bone); -SOKOL_SPINE_API_DECL void sspine_set_bone_transform(sspine_instance instance, sspine_bone bone, const sspine_bone_transform* transform); -SOKOL_SPINE_API_DECL void sspine_set_bone_position(sspine_instance instance, sspine_bone bone, sspine_vec2 position); -SOKOL_SPINE_API_DECL void sspine_set_bone_rotation(sspine_instance instance, sspine_bone bone, float rotation); -SOKOL_SPINE_API_DECL void sspine_set_bone_scale(sspine_instance instance, sspine_bone bone, sspine_vec2 scale); -SOKOL_SPINE_API_DECL void sspine_set_bone_shear(sspine_instance instance, sspine_bone bone, sspine_vec2 shear); -SOKOL_SPINE_API_DECL sspine_bone_transform sspine_get_bone_transform(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_bone_position(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL float sspine_get_bone_rotation(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_bone_scale(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_bone_shear(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_get_bone_world_position(sspine_instance instance, sspine_bone bone); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_bone_local_to_world(sspine_instance instance, sspine_bone bone, sspine_vec2 local_pos); -SOKOL_SPINE_API_DECL sspine_vec2 sspine_bone_world_to_local(sspine_instance instance, sspine_bone bone, sspine_vec2 world_pos); - -// slot functions -SOKOL_SPINE_API_DECL int sspine_num_slots(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_slot sspine_slot_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_slot sspine_slot_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_slot_valid(sspine_slot slot); -SOKOL_SPINE_API_DECL bool sspine_slot_equal(sspine_slot first, sspine_slot second); -SOKOL_SPINE_API_DECL sspine_slot_info sspine_get_slot_info(sspine_slot slot); -SOKOL_SPINE_API_DECL void sspine_set_slot_color(sspine_instance instance, sspine_slot slot, sspine_color color); -SOKOL_SPINE_API_DECL sspine_color sspine_get_slot_color(sspine_instance instance, sspine_slot slot); - -// event functions -SOKOL_SPINE_API_DECL int sspine_num_events(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_event sspine_event_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_event sspine_event_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_event_valid(sspine_event event); -SOKOL_SPINE_API_DECL bool sspine_event_equal(sspine_event first, sspine_event second); -SOKOL_SPINE_API_DECL sspine_event_info sspine_get_event_info(sspine_event event); - -// ik target functions -SOKOL_SPINE_API_DECL int sspine_num_iktargets(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_iktarget sspine_iktarget_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_iktarget sspine_iktarget_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_iktarget_valid(sspine_iktarget iktarget); -SOKOL_SPINE_API_DECL bool sspine_iktarget_equal(sspine_iktarget first, sspine_iktarget second); -SOKOL_SPINE_API_DECL sspine_iktarget_info sspine_get_iktarget_info(sspine_iktarget iktarget); -SOKOL_SPINE_API_DECL void sspine_set_iktarget_world_pos(sspine_instance instance, sspine_iktarget iktarget, sspine_vec2 world_pos); - -// skin functions -SOKOL_SPINE_API_DECL int sspine_num_skins(sspine_skeleton skeleton); -SOKOL_SPINE_API_DECL sspine_skin sspine_skin_by_name(sspine_skeleton skeleton, const char* name); -SOKOL_SPINE_API_DECL sspine_skin sspine_skin_by_index(sspine_skeleton skeleton, int index); -SOKOL_SPINE_API_DECL bool sspine_skin_valid(sspine_skin skin); -SOKOL_SPINE_API_DECL bool sspine_skin_equal(sspine_skin first, sspine_skin second); -SOKOL_SPINE_API_DECL sspine_skin_info sspine_get_skin_info(sspine_skin skin); -SOKOL_SPINE_API_DECL void sspine_set_skin(sspine_instance instance, sspine_skin skin); - -#ifdef __cplusplus -} // extern "C" -#endif - -// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ -// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ -// -// >>implementation -#ifdef SOKOL_SPINE_IMPL -#define SOKOL_SPINE_IMPL_INCLUDED (1) - -#if !defined(SPINE_SPINE_H_) -#error "Please include spine/spine.h before the sokol_spine.h implementation" -#endif - -#ifndef SOKOL_API_IMPL - #define SOKOL_API_IMPL -#endif -#ifndef SOKOL_DEBUG - #ifndef NDEBUG - #define SOKOL_DEBUG (1) - #endif -#endif -#ifndef SOKOL_ASSERT - #include - #define SOKOL_ASSERT(c) assert(c) -#endif -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) -#endif -#ifndef SOKOL_UNUSED - #define SOKOL_UNUSED(x) (void)(x) -#endif - -#include // malloc/free -#include // memset, strcmp - -// ███████╗██╗ ██╗ █████╗ ██████╗ ███████╗██████╗ ███████╗ -// ██╔════╝██║ ██║██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔════╝ -// ███████╗███████║███████║██║ ██║█████╗ ██████╔╝███████╗ -// ╚════██║██╔══██║██╔══██║██║ ██║██╔══╝ ██╔══██╗╚════██║ -// ███████║██║ ██║██║ ██║██████╔╝███████╗██║ ██║███████║ -// ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝╚══════╝ -// -// >>shaders -/* - Embedded source compiled with: - - sokol-shdc -i sspine.glsl -o sspine.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b - - @vs vs - uniform vs_params { - mat4 mvp; - }; - in vec2 position; - in vec2 texcoord0; - in vec4 color0; - out vec2 uv; - out vec4 color; - void main() { - gl_Position = mvp * vec4(position, 0.0, 1.0); - uv = texcoord0; - color = color0; - } - @end - - @fs fs - uniform texture2D tex; - uniform sampler smp; - uniform fs_params { - float pma; - }; - in vec2 uv; - in vec4 color; - out vec4 frag_color; - void main() { - vec4 c0 = texture(sampler2D(tex, smp), uv) * color; - vec4 c1 = vec4(c0.rgb * c0.a, c0.a) * color; - frag_color = mix(c0, c1, pma); - } - @end - - @program sspine vs fs -*/ -#if defined(SOKOL_GLCORE) -static const uint8_t _sspine_vs_source_glsl410[394] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, - 0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76, - 0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c, - 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, - 0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29, - 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72, - 0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x5b,0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b, - 0x32,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d, - 0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30, - 0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sspine_fs_source_glsl410[350] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, - 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d, - 0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73, - 0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, - 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, - 0x32,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63, - 0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65, - 0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, - 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29, - 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x34,0x20,0x5f,0x32,0x38,0x20, - 0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d, - 0x70,0x2c,0x20,0x75,0x76,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x33,0x37,0x20,0x3d,0x20, - 0x5f,0x32,0x38,0x2e,0x77,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x6d,0x69,0x78,0x28,0x5f,0x32,0x38,0x2c, - 0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x32,0x38,0x2e,0x78,0x79,0x7a,0x20,0x2a,0x20, - 0x5f,0x33,0x37,0x2c,0x20,0x5f,0x33,0x37,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x2c,0x20,0x76,0x65,0x63,0x34,0x28,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x5b,0x30,0x5d,0x2e,0x78,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_GLES3) -static const uint8_t _sspine_vs_source_glsl300es[355] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, - 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, - 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a, - 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20, - 0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f, - 0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x6d,0x61, - 0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2c, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63, - 0x34,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c, - 0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d, - 0x0a,0x0a,0x00, -}; -static const uint8_t _sspine_fs_source_glsl300es[399] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, - 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, - 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, - 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63, - 0x34,0x20,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a, - 0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61, - 0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b, - 0x0a,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20, - 0x75,0x76,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63, - 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75, - 0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61, - 0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, - 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68, - 0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x5f,0x32,0x38,0x20,0x3d,0x20,0x74,0x65,0x78, - 0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76, - 0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x68, - 0x69,0x67,0x68,0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x33,0x37,0x20,0x3d, - 0x20,0x5f,0x32,0x38,0x2e,0x77,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67, - 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x6d,0x69,0x78,0x28,0x5f,0x32,0x38, - 0x2c,0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x32,0x38,0x2e,0x78,0x79,0x7a,0x20,0x2a, - 0x20,0x5f,0x33,0x37,0x2c,0x20,0x5f,0x33,0x37,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c, - 0x6f,0x72,0x2c,0x20,0x76,0x65,0x63,0x34,0x28,0x66,0x73,0x5f,0x70,0x61,0x72,0x61, - 0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_D3D11) -static const uint8_t _sspine_vs_bytecode_hlsl4[844] = { - 0x44,0x58,0x42,0x43,0x2a,0xc9,0x57,0x52,0x4b,0x3d,0x3e,0x89,0x00,0xf4,0xfa,0x41, - 0xfd,0xd7,0x63,0xc3,0x01,0x00,0x00,0x00,0x4c,0x03,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0xf4,0x00,0x00,0x00,0x58,0x01,0x00,0x00,0xc8,0x01,0x00,0x00, - 0xd0,0x02,0x00,0x00,0x52,0x44,0x45,0x46,0xb8,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, - 0x10,0x81,0x00,0x00,0x90,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, - 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00, - 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x80,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x31,0x39,0x5f,0x6d,0x76,0x70,0x00,0x02,0x00,0x03,0x00, - 0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0x69,0x63,0x72, - 0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53, - 0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31, - 0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43, - 0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0c,0x00,0x00, - 0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69, - 0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab,0x53,0x48,0x44,0x52,0x00,0x01,0x00,0x00, - 0x40,0x00,0x01,0x00,0x40,0x00,0x00,0x00,0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00, - 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00, - 0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00,0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03, - 0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00, - 0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04,0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05, - 0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00,0x01,0x00,0x00,0x00, - 0x36,0x00,0x00,0x05,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00, - 0x02,0x00,0x00,0x00,0x38,0x00,0x00,0x08,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x56,0x15,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x06,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08, - 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3e,0x00,0x00,0x01, - 0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sspine_fs_bytecode_hlsl4[868] = { - 0x44,0x58,0x42,0x43,0xfb,0x9d,0xdb,0x19,0x85,0xbc,0x50,0x5d,0x6b,0x03,0xd4,0xc8, - 0x1b,0xea,0x59,0xf5,0x01,0x00,0x00,0x00,0x64,0x03,0x00,0x00,0x05,0x00,0x00,0x00, - 0x34,0x00,0x00,0x00,0x3c,0x01,0x00,0x00,0x88,0x01,0x00,0x00,0xbc,0x01,0x00,0x00, - 0xe8,0x02,0x00,0x00,0x52,0x44,0x45,0x46,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x00, - 0x90,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, - 0x10,0x81,0x00,0x00,0xd8,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00, - 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x73,0x6d,0x70,0x00,0x74,0x65,0x78,0x00, - 0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x00,0xab,0xab,0x84,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x35,0x33,0x5f, - 0x70,0x6d,0x61,0x00,0x00,0x00,0x03,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52, - 0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e, - 0x44,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x03,0x00,0x00,0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43, - 0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab,0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00, - 0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, - 0x53,0x56,0x5f,0x54,0x61,0x72,0x67,0x65,0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52, - 0x24,0x01,0x00,0x00,0x40,0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x59,0x00,0x00,0x04, - 0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x5a,0x00,0x00,0x03, - 0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00,0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00, - 0x00,0x00,0x00,0x00,0x55,0x55,0x00,0x00,0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00, - 0x00,0x00,0x00,0x00,0x62,0x10,0x00,0x03,0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00, - 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02, - 0x02,0x00,0x00,0x00,0x45,0x00,0x00,0x09,0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00, - 0x46,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00, - 0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xf2,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00, - 0x01,0x00,0x00,0x00,0x38,0x00,0x00,0x07,0x72,0x00,0x10,0x00,0x01,0x00,0x00,0x00, - 0xf6,0x0f,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x02,0x10,0x00,0x00,0x00,0x00,0x00, - 0x36,0x00,0x00,0x05,0x82,0x00,0x10,0x00,0x01,0x00,0x00,0x00,0x3a,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x0a,0xf2,0x00,0x10,0x00,0x01,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00, - 0x46,0x0e,0x10,0x80,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x0a, - 0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x06,0x80,0x20,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00,0x01,0x00,0x00,0x00,0x46,0x0e,0x10,0x00, - 0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x01,0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00, - 0x07,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, - 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, -}; -#elif defined(SOKOL_METAL) -static const uint8_t _sspine_vs_bytecode_metal_macos[3084] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x1d,0x26,0xf7,0xce,0x5d,0x78,0x21, - 0x2f,0xa7,0x97,0xe1,0xbd,0x15,0x30,0xfb,0xa6,0x98,0xcc,0x1d,0xba,0x1d,0x0d,0x92, - 0xaa,0x4e,0x3d,0x75,0xee,0x73,0x36,0x7c,0x99,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xe0,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xb5,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x14,0x45,0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x81,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x18,0x02,0x01,0x2c,0x40,0x05,0x00,0x49,0x18,0x00,0x00, - 0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00,0x1f,0x00,0x00,0x00, - 0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3, - 0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x44,0x33,0x00, - 0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x42,0x24,0x81,0x98,0x89,0x9a,0x07, - 0x7a,0x90,0x87,0x7a,0x18,0x07,0x7a,0x70,0x83,0x76,0x28,0x07,0x7a,0x08,0x07,0x76, - 0xd0,0x03,0x3d,0x68,0x87,0x70,0xa0,0x07,0x79,0x48,0x07,0x7c,0x40,0x01,0x39,0x48, - 0x9a,0x22,0x4a,0x98,0xfc,0x4a,0xfa,0x1f,0x20,0x02,0x18,0x09,0x05,0x65,0x10,0xc1, - 0x10,0x4a,0x31,0x42,0x10,0x87,0xd0,0x40,0xc0,0x1c,0x01,0x18,0xa4,0xc0,0x9a,0x23, - 0x00,0x85,0x41,0x04,0x41,0x18,0x46,0x20,0x96,0x11,0x00,0x00,0x13,0xb2,0x70,0x48, - 0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83, - 0x76,0x08,0x87,0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38, - 0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0, - 0x07,0x78,0xd0,0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e, - 0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73, - 0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40, - 0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07, - 0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a, - 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10, - 0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, - 0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0, - 0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07, - 0x76,0x40,0x07,0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a, - 0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20, - 0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07, - 0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72, - 0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0, - 0x06,0xf6,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07, - 0x71,0x20,0x07,0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70, - 0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0, - 0x07,0x71,0x60,0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00, - 0x00,0x00,0x00,0xc8,0x02,0x01,0x00,0x00,0x0a,0x00,0x00,0x00,0x32,0x1e,0x98,0x10, - 0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50, - 0x04,0x05,0x18,0x50,0x08,0x05,0x51,0x06,0x05,0x42,0x6d,0x04,0x80,0xd8,0x58,0x42, - 0x13,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xeb,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10, - 0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32,0x28, - 0x00,0xa3,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c, - 0x81,0x22,0x2c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c, - 0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5, - 0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06, - 0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25,0x58, - 0x8c,0x45,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82,0x45, - 0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6, - 0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50,0x12, - 0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73, - 0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x65, - 0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9, - 0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d, - 0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c,0x8b, - 0x5d,0x99,0x1c,0x5d,0x19,0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9, - 0x32,0x39,0x14,0xb6,0xb7,0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72, - 0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2, - 0xe8,0x64,0xc8,0x84,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51, - 0xa8,0xb3,0x1b,0xc2,0x28,0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9,0x9b, - 0x2b,0x93,0x43,0x61,0x7b,0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6,0xf6,0x16,0x46,0x47, - 0xc3,0x62,0xec,0x8d,0xed,0x4d,0x6e,0x08,0xa3,0x3c,0x8a,0xa5,0x44,0xca,0xa5,0x4c, - 0x0a,0x46,0x26,0x2c,0x4d,0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x8d,0xcb, - 0x19,0xdb,0x17,0xd4,0xdb,0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10,0x45,0xd1,0x94,0x48, - 0xb9,0x94,0x49,0xd9,0x86,0x18,0x4a,0xa5,0x64,0x0a,0x47,0x28,0x2c,0x4d,0xce,0xc5, - 0xae,0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c, - 0x0b,0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xbd, - 0xb3,0x32,0xb7,0x32,0xb9,0x30,0xba,0x32,0x32,0x94,0xaf,0xaf,0xb0,0x34,0xb9,0x2f, - 0x38,0xb6,0xb0,0xb1,0x32,0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf,0xaf,0x14,0x22,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43,0xa8,0x45,0x50,0x3c,0xe5,0x5b,0x84,0x25, - 0x50,0xc0,0x40,0x89,0x14,0x49,0x99,0x94,0x30,0x60,0x42,0x57,0x86,0x37,0xf6,0xf6, - 0x26,0x47,0x06,0x33,0x84,0x5a,0x02,0xc5,0x53,0xbe,0x25,0x58,0x02,0x05,0x0c,0x94, - 0x48,0x91,0x94,0x49,0x19,0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x65, - 0x50,0x3c,0xe5,0x5b,0x86,0x25,0x50,0xc0,0x40,0x89,0x94,0x4b,0x99,0x94,0x32,0xa0, - 0x12,0x96,0x26,0xe7,0x22,0x56,0x67,0x66,0x56,0x26,0xc7,0x27,0x2c,0x4d,0xce,0x45, - 0xac,0xce,0xcc,0xac,0x4c,0xee,0x6b,0x2e,0x4d,0xaf,0x8c,0x48,0x58,0x9a,0x9c,0x8b, - 0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39,0x97,0x39,0x3a,0xb9,0xba,0x31,0xba,0x2f, - 0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3,0x37,0x22,0x66,0x6c,0x6f,0x61,0x74,0x34, - 0x78,0x34,0x1c,0xda,0xec,0xe0,0x86,0x28,0x8b,0xb0,0x10,0x8b,0xa0,0xac,0x81,0xc2, - 0x06,0x8c,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0,0xca,0xbe,0xe6, - 0xd2,0xf4,0xca,0x78,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5,0xc1,0x95, - 0x7d,0x85,0xb1,0xa5,0x9d,0xb9,0x7d,0xcd,0xa5,0xe9,0x95,0x31,0xb1,0x9b,0xfb,0x82, - 0x0b,0x93,0x0b,0x6b,0x9b,0xe3,0xf0,0x15,0x93,0x33,0x84,0x0c,0x96,0x43,0x39,0x03, - 0x05,0x0d,0x16,0x42,0xf9,0x16,0x61,0x09,0x94,0x34,0x50,0xd4,0x40,0x69,0x03,0xc5, - 0x0d,0x16,0x42,0x79,0x83,0x05,0x51,0x22,0x05,0x0e,0x94,0x49,0x89,0x83,0x21,0x88, - 0x22,0x06,0x0a,0x19,0x28,0x66,0xa0,0xc8,0xc1,0x10,0x23,0x01,0x94,0x4e,0x99,0x03, - 0x3e,0x6f,0x6d,0x6e,0x69,0x70,0x6f,0x74,0x65,0x6e,0x74,0x20,0x63,0x68,0x61,0x72, - 0x7c,0xa6,0xd2,0xda,0xe0,0xd8,0xca,0x40,0x86,0x56,0x56,0x40,0xa8,0x84,0x82,0x82, - 0x86,0x08,0x8a,0x1d,0x0c,0x31,0x94,0x3a,0x50,0xee,0xa0,0x49,0x86,0x18,0x0a,0x1e, - 0x28,0x78,0xd0,0x24,0x23,0x22,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x77, - 0x20,0x87,0x7a,0x60,0x87,0x72,0x70,0x03,0x73,0x60,0x87,0x70,0x38,0x87,0x79,0x98, - 0x22,0x04,0xc3,0x08,0x85,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xd2,0x81,0x1c,0xca, - 0xc1,0x1d,0xe8,0x61,0x4a,0x50,0x8c,0x58,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xec,0xa1, - 0x1c,0xe4,0x61,0x1e,0xd2,0xe1,0x1d,0xdc,0x61,0x4a,0x60,0x8c,0xa0,0xc2,0x21,0x1d, - 0xe4,0xc1,0x0d,0xd8,0x21,0x1c,0xdc,0xe1,0x1c,0xea,0x21,0x1c,0xce,0xa1,0x1c,0x7e, - 0xc1,0x1e,0xca,0x41,0x1e,0xe6,0x21,0x1d,0xde,0xc1,0x1d,0xa6,0x04,0xc8,0x88,0x29, - 0x1c,0xd2,0x41,0x1e,0xdc,0x60,0x1c,0xde,0xa1,0x1d,0xe0,0x21,0x1d,0xd8,0xa1,0x1c, - 0x7e,0xe1,0x1d,0xe0,0x81,0x1e,0xd2,0xe1,0x1d,0xdc,0x61,0x1e,0xa6,0x0c,0x0a,0xe3, - 0x8c,0x50,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xec,0xa1,0x1c,0xe4,0x81,0x1e,0xca,0x01, - 0x1f,0xa6,0x04,0x74,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00, - 0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3, - 0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10, - 0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30, - 0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03, - 0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07, - 0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e, - 0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d, - 0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b, - 0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76, - 0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90, - 0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87, - 0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e, - 0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c, - 0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca, - 0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8, - 0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82, - 0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83, - 0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f, - 0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec, - 0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc, - 0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0, - 0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60, - 0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e, - 0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1, - 0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43, - 0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c, - 0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72, - 0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1, - 0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38, - 0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8, - 0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00, - 0x02,0x00,0x00,0x00,0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00, - 0x1e,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x05,0x00,0x00,0x00, - 0xf4,0xc6,0x22,0x82,0x20,0x08,0x46,0x00,0xa8,0x95,0x40,0x19,0xd0,0x98,0x01,0xa0, - 0x30,0x03,0x00,0x00,0xe3,0x15,0x07,0x33,0x4d,0x0c,0x05,0x65,0x90,0x81,0x19,0x0e, - 0x13,0x02,0xf9,0x8c,0x57,0x2c,0xd0,0x75,0x21,0x14,0x94,0x41,0x06,0xe8,0x60,0x4c, - 0x08,0xe4,0x63,0x41,0x01,0x9f,0xf1,0x0a,0xa8,0xe2,0x38,0x86,0x82,0x62,0x43,0x00, - 0x9f,0xd9,0x06,0xa7,0x02,0x66,0x1b,0x82,0x2a,0x98,0x6d,0x08,0x06,0x21,0x83,0x80, - 0x18,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x5b,0x86,0x20,0xc8,0x83,0x2d,0x43,0x11, - 0xe4,0xc1,0x96,0x41,0x09,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sspine_fs_bytecode_metal_macos[3257] = { - 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xb9,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xe0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0x47,0xc7,0x1e,0x49,0x53,0x1c,0xe5, - 0x90,0x01,0xa5,0x57,0x9a,0x30,0x01,0x5c,0x39,0x85,0x9f,0xb2,0x71,0x51,0xe1,0x73, - 0x0c,0xa4,0x4d,0xb1,0x81,0x33,0x8d,0x17,0x1e,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0xc4,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0xee,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x8e,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81,0x00,0x16,0xa0,0xda, - 0x60,0x10,0x05,0xb0,0x00,0xd5,0x06,0xa3,0xf8,0xff,0xff,0xff,0xff,0x01,0x90,0x00, - 0x6a,0x03,0x62,0xfc,0xff,0xff,0xff,0xff,0x00,0x30,0x80,0x04,0x54,0x1b,0x8c,0x23, - 0x00,0x16,0xa0,0xda,0x60,0x20,0x02,0xb0,0x00,0x15,0x00,0x00,0x00,0x49,0x18,0x00, - 0x00,0x03,0x00,0x00,0x00,0x13,0x88,0x40,0x18,0x88,0x09,0x41,0x31,0x61,0x30,0x0e, - 0x04,0x89,0x20,0x00,0x00,0x27,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, - 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, - 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x6c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c, - 0x20,0x00,0x07,0x49,0x53,0x44,0x09,0x93,0x5f,0x48,0xff,0x03,0x44,0x00,0x23,0xa1, - 0x00,0x0c,0x22,0x10,0xc2,0x51,0xd2,0x14,0x51,0xc2,0xe4,0xff,0x13,0x71,0x4d,0x54, - 0x44,0xfc,0xf6,0xf0,0x4f,0x63,0x04,0xc0,0x20,0x82,0x11,0x5c,0x24,0x4d,0x11,0x25, - 0x4c,0xfe,0x2f,0x01,0xcc,0xb3,0x10,0xd1,0x3f,0x8d,0x11,0x00,0x83,0x08,0x88,0x50, - 0x0c,0x31,0x42,0x39,0x89,0x54,0x21,0x42,0x08,0x81,0xd8,0x1c,0x41,0x30,0x47,0x00, - 0x06,0xc3,0x08,0xc2,0x53,0x90,0x70,0xd2,0x70,0xd0,0x01,0x8a,0x03,0x01,0x29,0xf0, - 0x86,0x11,0x86,0x67,0x18,0x61,0x00,0x86,0x11,0x88,0x67,0x8e,0x00,0x14,0x06,0x11, - 0x00,0x61,0x04,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83, - 0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87,0x71,0x78,0x87,0x79, - 0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5, - 0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x80,0x07, - 0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07,0x7a,0x10,0x07,0x76, - 0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0, - 0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07, - 0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, - 0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07, - 0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d, - 0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60, - 0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f, - 0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x79, - 0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60, - 0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07, - 0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a, - 0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50, - 0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50,0x07,0x71,0x20,0x07, - 0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x6d,0x60,0x0f,0x71, - 0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00, - 0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60,0x07,0x7a,0x30,0x07, - 0x72,0x30,0x84,0x59,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x18,0xc2,0x34,0x40, - 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x0c,0x61,0x24,0x20,0x00,0x06,0x00,0x00,0x00, - 0x00,0x00,0xb2,0x40,0x00,0x09,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c, - 0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x7a,0x23,0x00,0x25,0x50,0x08,0x45,0x50, - 0x10,0x65,0x40,0x78,0x04,0x80,0xe8,0x58,0x42,0x13,0x00,0x00,0x00,0x79,0x18,0x00, - 0x00,0xf9,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32, - 0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x63,0x4c,0x00,0xa5,0x50,0xb9,0x1b,0x43,0x0b, - 0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x3c,0xc4,0x24,0x3c,0x05,0xe7,0x20,0x08, - 0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed, - 0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c, - 0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45, - 0x26,0x65,0x88,0x30,0x11,0x43,0x8c,0x87,0x78,0x8e,0x67,0x60,0xd1,0x54,0x46,0x17, - 0xc6,0x36,0x04,0x99,0x8e,0x87,0x78,0x88,0x67,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6, - 0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96, - 0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x98,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f, - 0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f, - 0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x69,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c, - 0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99, - 0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95, - 0x0d,0x11,0xa6,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17, - 0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba, - 0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x64, - 0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc,0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85, - 0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61,0xa6,0xe7,0x19,0x26,0x68,0x8a,0x26, - 0x69,0x9a,0x86,0x08,0x13,0x45,0x29,0x2c,0x4d,0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad, - 0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb, - 0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39,0x97,0xb1,0x32,0x37,0xba,0x32,0x39, - 0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73,0x70,0x65,0x63,0x74,0x69,0x76,0x65, - 0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28,0xd4,0xd9,0x0d,0x91,0x9e,0x61,0xb2,0xa6, - 0x6b,0xc2,0xa6,0x6c,0x82,0x26,0x6d,0x92,0xa6,0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a, - 0xdb,0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1,0x37,0xb6,0x37,0xb9,0x21,0xd2,0x43,0x4c, - 0xd6,0xd4,0x4d,0xd8,0x94,0x4d,0xd0,0x14,0x4d,0xd2,0xe4,0x51,0x09,0x4b,0x93,0x73, - 0x11,0xab,0x33,0x33,0x2b,0x93,0xe3,0x13,0x96,0x26,0xe7,0x22,0x56,0x67,0x66,0x56, - 0x26,0xf7,0x35,0x97,0xa6,0x57,0x46,0x29,0x2c,0x4d,0xce,0x85,0xed,0x6d,0x2c,0x8c, - 0x2e,0xed,0xcd,0xed,0x2b,0xcd,0x8d,0xac,0x0c,0x8f,0x48,0x58,0x9a,0x9c,0x8b,0x5c, - 0x59,0x18,0x19,0xa9,0xb0,0x34,0x39,0x97,0x39,0x3a,0xb9,0xba,0x31,0xba,0x2f,0xba, - 0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3,0x37,0x16,0x66,0x6c,0x6f,0x61,0x74,0x1c,0xe0, - 0xda,0xc2,0x86,0x28,0xcf,0xf0,0x14,0xcf,0x30,0x95,0xc1,0x64,0x06,0x8c,0xc2,0xd2, - 0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0,0xca,0xbe,0xe6,0xd2,0xf4,0xca,0x78, - 0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5,0xc1,0x95,0x7d,0x85,0xb1,0xa5, - 0x9d,0xb9,0x7d,0xcd,0xa5,0xe9,0x95,0x31,0x31,0x9b,0xfb,0x82,0x0b,0x93,0x0b,0x6b, - 0x9b,0xe3,0xf0,0x55,0x33,0x33,0x84,0x0c,0x1e,0x63,0x02,0x83,0x29,0x0c,0x9e,0x62, - 0x12,0x83,0x67,0x78,0x88,0x69,0x0c,0x26,0x32,0x98,0xce,0x60,0x42,0x83,0xa7,0x98, - 0xd2,0xe0,0x29,0x26,0x68,0x52,0x83,0x49,0x9a,0xd6,0x80,0x4b,0x58,0x9a,0x9c,0x0b, - 0x5d,0x19,0x1e,0x5d,0x9d,0x5c,0x19,0x95,0xb0,0x34,0x39,0x97,0xb9,0xb0,0x36,0x38, - 0xb6,0x32,0x62,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f, - 0x61,0x74,0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x3e,0x1c,0xe8,0xca,0xf0,0x86, - 0x50,0x0f,0x32,0xb5,0xc1,0x24,0x06,0xcf,0xf0,0x10,0x93,0x1b,0x4c,0xd0,0xf4,0x06, - 0x93,0x34,0xc1,0x01,0x97,0xb0,0x34,0x39,0x97,0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39, - 0x1e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x1c,0xe6,0xda,0xe0,0x86,0x48,0x4f,0x31, - 0xc9,0xc1,0x24,0x06,0xcf,0xf0,0x10,0x13,0x34,0xcd,0xc1,0x24,0x4d,0x74,0x30,0x44, - 0x99,0xb8,0xe9,0x9b,0xd8,0x60,0x8a,0x83,0xa9,0x0e,0x86,0x18,0x0b,0x30,0x55,0x93, - 0x1d,0xd0,0xf9,0xd2,0xa2,0x9a,0xca,0x31,0x9b,0xfb,0x82,0x0b,0x93,0x0b,0x6b,0x9b, - 0xe3,0xf3,0xd6,0xe6,0x96,0x06,0xf7,0x46,0x57,0xe6,0x46,0x07,0x32,0x86,0x16,0x26, - 0xc7,0x67,0x2a,0xad,0x0d,0x8e,0xad,0x0c,0x64,0x68,0x65,0x05,0x84,0x4a,0x28,0x28, - 0x68,0x88,0x30,0xe9,0xc1,0x10,0x63,0xca,0x83,0x69,0x0f,0xb0,0x64,0x88,0x31,0x95, - 0xc1,0xc4,0x07,0x58,0x32,0xc4,0x98,0xf0,0x60,0xea,0x03,0x2c,0x19,0x62,0x4c,0x7e, - 0x30,0xf5,0x01,0x96,0x8c,0x88,0xd8,0x81,0x1d,0xec,0xa1,0x1d,0xdc,0xa0,0x1d,0xde, - 0x81,0x1c,0xea,0x81,0x1d,0xca,0xc1,0x0d,0xcc,0x81,0x1d,0xc2,0xe1,0x1c,0xe6,0x61, - 0x8a,0x10,0x0c,0x23,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x48,0x07,0x72,0x28, - 0x07,0x77,0xa0,0x87,0x29,0x41,0x31,0x62,0x09,0x87,0x74,0x90,0x07,0x37,0xb0,0x87, - 0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x81,0x31,0x82,0x0a,0x87,0x74, - 0x90,0x07,0x37,0x60,0x87,0x70,0x70,0x87,0x73,0xa8,0x87,0x70,0x38,0x87,0x72,0xf8, - 0x05,0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78,0x07,0x77,0x98,0x12,0x20,0x23,0xa6, - 0x70,0x48,0x07,0x79,0x70,0x83,0x71,0x78,0x87,0x76,0x80,0x87,0x74,0x60,0x87,0x72, - 0xf8,0x85,0x77,0x80,0x07,0x7a,0x48,0x87,0x77,0x70,0x87,0x79,0x98,0x32,0x28,0x8c, - 0x33,0x82,0x09,0x87,0x74,0x90,0x07,0x37,0x30,0x07,0x79,0x08,0x87,0x73,0x68,0x87, - 0x72,0x70,0x07,0x7a,0x98,0x12,0xdc,0x01,0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00, - 0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84, - 0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed, - 0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66, - 0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c, - 0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70, - 0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90, - 0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4, - 0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83, - 0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14, - 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70, - 0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80, - 0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0, - 0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1, - 0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d, - 0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39, - 0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc, - 0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70, - 0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53, - 0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e, - 0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c, - 0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38, - 0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37, - 0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33, - 0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4, - 0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0, - 0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3, - 0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07, - 0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23, - 0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59, - 0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b, - 0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00, - 0x00,0x0b,0x00,0x00,0x00,0x26,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f, - 0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20, - 0x0d,0x6d,0x01,0x0d,0x80,0x44,0x3e,0x83,0x5c,0x7e,0x85,0x17,0xb7,0x0d,0x00,0x00, - 0x00,0x61,0x20,0x00,0x00,0x25,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00, - 0x00,0x0c,0x00,0x00,0x00,0x74,0x47,0x00,0xc6,0x22,0x80,0x40,0x38,0xe6,0x20,0x06, - 0xc2,0xa8,0xc8,0xd5,0xc0,0x08,0x00,0xbd,0x19,0x00,0x82,0x23,0x00,0x54,0xc7,0x1a, - 0x80,0x40,0x18,0x6b,0x18,0x86,0x81,0xec,0x0c,0x00,0x89,0x19,0x00,0x0a,0x33,0x00, - 0x04,0x46,0x00,0x00,0x00,0x23,0x06,0xca,0x10,0x6c,0x8f,0x23,0x29,0x47,0x12,0x58, - 0x20,0xc9,0x67,0x90,0x21,0x20,0x90,0x41,0x06,0xa1,0x40,0x4c,0x08,0xe4,0x33,0xc8, - 0x10,0x24,0xd0,0x20,0x43,0x50,0x48,0x16,0x60,0xf2,0x19,0x6f,0xc0,0x38,0x31,0xa0, - 0x60,0xcc,0x31,0x30,0x01,0x19,0x0c,0x32,0x04,0x0d,0x36,0x62,0x60,0x08,0x01,0x1a, - 0x2c,0x45,0x30,0xdb,0x00,0x05,0x40,0x06,0x01,0x31,0x00,0x00,0x00,0x02,0x00,0x00, - 0x00,0x5b,0x86,0x24,0xf8,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sspine_vs_bytecode_metal_ios[3068] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xfc,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf0,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0x93,0xd6,0x91,0x34,0xa6,0x5a,0xef, - 0xf4,0xa9,0x2b,0xc7,0x55,0x75,0x4a,0x7f,0xc5,0x46,0xc0,0x95,0x92,0x61,0x00,0x3e, - 0x6d,0x53,0x68,0xee,0xb6,0x8e,0xc8,0x26,0x6c,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x37,0x00,0x00,0x00,0x56,0x41,0x54, - 0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x80, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80,0x63,0x6f,0x6c,0x6f, - 0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03,0x00,0x04,0x04,0x06, - 0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b, - 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xd8,0x0a,0x00,0x00,0xff,0xff,0xff,0xff, - 0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xb3,0x02,0x00,0x00,0x0b,0x82,0x20,0x00, - 0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49, - 0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62, - 0x80,0x14,0x45,0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49, - 0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72, - 0x24,0x07,0xc8,0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00, - 0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8,0xff,0xff,0xff,0xff, - 0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87,0x71,0xa0,0x07,0x76, - 0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72,0x20,0x87,0x36,0x20, - 0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88,0x07,0x79,0xa0,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0xc0,0x1c,0xc2,0x81, - 0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c, - 0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c,0xd8,0x81,0x1d,0xe6, - 0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87,0x72,0x98,0x87,0x79, - 0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72,0x68,0x03,0x73,0x80, - 0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xdc, - 0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda,0x00,0x1e,0xde,0x21, - 0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21,0x1d,0xda,0x01,0xa0, - 0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30,0x07,0x79,0x08,0x87, - 0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87,0x72,0x90,0x87,0x36, - 0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77,0x68,0x03,0x76,0x28, - 0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70,0x07,0x73,0x98,0x87, - 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, - 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1,0x1d,0xe0,0xa1,0x0d, - 0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87, - 0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87,0x79,0x68,0x03,0x73, - 0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c, - 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d,0xca,0x81,0x1c,0xda, - 0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0,0xa1,0x0d,0xda,0x21, - 0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80,0x70,0x87,0x77,0x68, - 0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38,0x87,0x36,0x68,0x87, - 0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0x62,0x1e,0xe8,0x21, - 0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1,0x1c,0xc6,0x81,0x1e, - 0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x0d,0xe6, - 0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87,0x79,0x08,0x07,0x73, - 0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e, - 0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d,0xe6,0xe1,0x1d,0xcc, - 0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00,0x73,0x08,0x07,0x76, - 0x98,0x87,0x72,0x00,0x36,0x20,0x02,0x01,0x24,0xc0,0x02,0x54,0x00,0x00,0x00,0x00, - 0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00, - 0x1f,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xa4,0x84, - 0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a,0x8c,0x0b,0x84,0xa4,0x4c, - 0x10,0x44,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x76,0x08,0x42,0x24,0x81, - 0x98,0x89,0x9a,0x07,0x7a,0x90,0x87,0x7a,0x18,0x07,0x7a,0x70,0x83,0x76,0x28,0x07, - 0x7a,0x08,0x07,0x76,0xd0,0x03,0x3d,0x68,0x87,0x70,0xa0,0x07,0x79,0x48,0x07,0x7c, - 0x40,0x01,0x39,0x48,0x9a,0x22,0x4a,0x98,0xfc,0x4a,0xfa,0x1f,0x20,0x02,0x18,0x09, - 0x05,0x65,0x10,0xc1,0x10,0x4a,0x31,0x42,0x10,0x87,0xd0,0x40,0xc0,0x1c,0x01,0x18, - 0xa4,0xc0,0x9a,0x23,0x00,0x85,0x41,0x04,0x41,0x18,0x46,0x20,0x96,0x11,0x00,0x00, - 0x13,0xa8,0x70,0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60, - 0x87,0x72,0x68,0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83, - 0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d, - 0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07, - 0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76, - 0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20, - 0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a, - 0x10,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30, - 0x07,0x72,0xd0,0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07, - 0x72,0xd0,0x06,0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, - 0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0, - 0x06,0xf6,0x90,0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07, - 0x78,0xd0,0x06,0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a, - 0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50, - 0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07, - 0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75, - 0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0, - 0x06,0xf6,0x10,0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07, - 0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76, - 0xa0,0x07,0x73,0x20,0x07,0x43,0x98,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80, - 0x2c,0x10,0x00,0x00,0x0a,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90, - 0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x05,0x18,0x50, - 0x08,0x05,0x51,0x06,0x05,0x42,0x6d,0x04,0x80,0xd8,0x58,0x02,0x24,0x00,0x00,0x00, - 0x79,0x18,0x00,0x00,0xea,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25, - 0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x32,0x28,0x00,0xa3,0x50,0xb9, - 0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0x81,0x22,0x2c,0x05, - 0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e,0x8c,0x0d,0xc4,0xae,0x4c, - 0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6,0xe6,0x06,0x04, - 0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06,0x06,0x26,0xc6,0xc5,0xc6, - 0xe6,0xc6,0x45,0x26,0x65,0x88,0xa0,0x10,0x43,0x8c,0x25,0x58,0x8c,0x45,0x60,0xd1, - 0x54,0x46,0x17,0xc6,0x36,0x04,0x51,0x8e,0x25,0x58,0x82,0x45,0xe0,0x16,0x96,0x26, - 0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36, - 0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x50,0x12,0x72,0x61,0x69,0x72, - 0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61, - 0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x65,0x21,0x19,0x84,0xa5, - 0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89, - 0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85,0x89, - 0xb1,0x95,0x0d,0x11,0x94,0x86,0x51,0x58,0x9a,0x9c,0x8b,0x5d,0x99,0x1c,0x5d,0x19, - 0xde,0xd7,0x5b,0x1d,0x1d,0x5c,0x1d,0x1d,0x97,0xba,0xb9,0x32,0x39,0x14,0xb6,0xb7, - 0x31,0x37,0x98,0x14,0x46,0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70, - 0x65,0x5f,0x6e,0x61,0x6d,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0xc8,0x84,0xa5, - 0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xb9,0x85,0xb5,0x95,0x51,0xa8,0xb3,0x1b,0xc2,0x28, - 0x8f,0x02,0x29,0x91,0x22,0x29,0x93,0x42,0x71,0xa9,0x9b,0x2b,0x93,0x43,0x61,0x7b, - 0x1b,0x73,0x8b,0x49,0xa1,0x61,0xc6,0xf6,0x16,0x46,0x47,0xc3,0x62,0xec,0x8d,0xed, - 0x4d,0x6e,0x08,0xa3,0x3c,0x8a,0xa5,0x44,0xca,0xa5,0x4c,0x0a,0x46,0x26,0x2c,0x4d, - 0xce,0x05,0xee,0x6d,0x2e,0x8d,0x2e,0xed,0xcd,0x8d,0xcb,0x19,0xdb,0x17,0xd4,0xdb, - 0x5c,0x1a,0x5d,0xda,0x9b,0xdb,0x10,0x45,0xd1,0x94,0x48,0xb9,0x94,0x49,0xd9,0x86, - 0x18,0x4a,0xa5,0x64,0x0a,0x47,0x28,0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c, - 0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18, - 0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xbd,0xb3,0x32,0xb7,0x32,0xb9, - 0x30,0xba,0x32,0x32,0x94,0xaf,0xaf,0xb0,0x34,0xb9,0x2f,0x38,0xb6,0xb0,0xb1,0x32, - 0xb4,0x37,0x36,0xb2,0x32,0xb9,0xaf,0xaf,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69, - 0x6f,0x6e,0x43,0xa8,0x45,0x50,0x3c,0xe5,0x5b,0x84,0x25,0x50,0xc0,0x40,0x89,0x14, - 0x49,0x99,0x94,0x30,0x60,0x42,0x57,0x86,0x37,0xf6,0xf6,0x26,0x47,0x06,0x33,0x84, - 0x5a,0x02,0xc5,0x53,0xbe,0x25,0x58,0x02,0x05,0x0c,0x94,0x48,0x91,0x94,0x49,0x19, - 0x03,0x1a,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x43,0xa8,0x65,0x50,0x3c,0xe5,0x5b,0x86, - 0x25,0x50,0xc0,0x40,0x89,0x94,0x4b,0x99,0x94,0x32,0xa0,0x12,0x96,0x26,0xe7,0x22, - 0x56,0x67,0x66,0x56,0x26,0xc7,0x27,0x2c,0x4d,0xce,0x45,0xac,0xce,0xcc,0xac,0x4c, - 0xee,0x6b,0x2e,0x4d,0xaf,0x8c,0x48,0x58,0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9, - 0xb0,0x34,0x39,0x97,0x39,0x3a,0xb9,0xba,0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf, - 0x34,0x37,0xb3,0x37,0x22,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x1c,0xda,0xec, - 0xe0,0x86,0x28,0x8b,0xb0,0x10,0x8b,0xa0,0xac,0x81,0xc2,0x06,0x8c,0xc2,0xd2,0xe4, - 0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0,0xca,0xbe,0xe6,0xd2,0xf4,0xca,0x78,0x85, - 0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1,0xe5,0xc1,0x95,0x7d,0x85,0xb1,0xa5,0x9d, - 0xb9,0x7d,0xcd,0xa5,0xe9,0x95,0x31,0xb1,0x9b,0xfb,0x82,0x0b,0x93,0x0b,0x6b,0x9b, - 0xe3,0xf0,0x15,0x93,0x33,0x84,0x0c,0x96,0x43,0x39,0x03,0x05,0x0d,0x16,0x42,0xf9, - 0x16,0x61,0x09,0x94,0x34,0x50,0xd4,0x40,0x69,0x03,0xc5,0x0d,0x16,0x42,0x79,0x83, - 0x05,0x51,0x22,0x05,0x0e,0x94,0x49,0x89,0x83,0x21,0x88,0x22,0x06,0x0a,0x19,0x28, - 0x66,0xa0,0xc8,0xc1,0x10,0x23,0x01,0x94,0x4e,0x99,0x03,0x3e,0x6f,0x6d,0x6e,0x69, - 0x70,0x6f,0x74,0x65,0x6e,0x74,0x20,0x63,0x68,0x61,0x72,0x7c,0xa6,0xd2,0xda,0xe0, - 0xd8,0xca,0x40,0x86,0x56,0x56,0x40,0xa8,0x84,0x82,0x82,0x86,0x08,0x8a,0x1d,0x0c, - 0x31,0x94,0x3a,0x50,0xee,0xa0,0x49,0x86,0x18,0x0a,0x1e,0x28,0x78,0xd0,0x24,0x23, - 0x22,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x77,0x20,0x87,0x7a,0x60,0x87, - 0x72,0x70,0x03,0x73,0x60,0x87,0x70,0x38,0x87,0x79,0x98,0x22,0x04,0xc3,0x08,0x85, - 0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xd2,0x81,0x1c,0xca,0xc1,0x1d,0xe8,0x61,0x4a, - 0x50,0x8c,0x58,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xec,0xa1,0x1c,0xe4,0x61,0x1e,0xd2, - 0xe1,0x1d,0xdc,0x61,0x4a,0x60,0x8c,0xa0,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xd8,0x21, - 0x1c,0xdc,0xe1,0x1c,0xea,0x21,0x1c,0xce,0xa1,0x1c,0x7e,0xc1,0x1e,0xca,0x41,0x1e, - 0xe6,0x21,0x1d,0xde,0xc1,0x1d,0xa6,0x04,0xc8,0x88,0x29,0x1c,0xd2,0x41,0x1e,0xdc, - 0x60,0x1c,0xde,0xa1,0x1d,0xe0,0x21,0x1d,0xd8,0xa1,0x1c,0x7e,0xe1,0x1d,0xe0,0x81, - 0x1e,0xd2,0xe1,0x1d,0xdc,0x61,0x1e,0xa6,0x0c,0x0a,0xe3,0x8c,0x50,0xc2,0x21,0x1d, - 0xe4,0xc1,0x0d,0xec,0xa1,0x1c,0xe4,0x81,0x1e,0xca,0x01,0x1f,0xa6,0x04,0x74,0x00, - 0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66, - 0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73, - 0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e, - 0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b, - 0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b, - 0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20, - 0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0, - 0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61, - 0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83, - 0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87, - 0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76, - 0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98, - 0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30, - 0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61, - 0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43, - 0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b, - 0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7, - 0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18, - 0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90, - 0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1, - 0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d, - 0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24, - 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c, - 0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d, - 0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54, - 0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4, - 0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18, - 0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec,0xc0, - 0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8,0xe1, - 0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4,0x83, - 0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43,0x3d, - 0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30,0x00, - 0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x1e,0x00,0x00,0x00,0x13,0x04,0x41,0x2c, - 0x10,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xf4,0xc6,0x22,0x82,0x20,0x08,0x46,0x00, - 0xa8,0x95,0x40,0x19,0xd0,0x98,0x01,0xa0,0x30,0x03,0x00,0x00,0xe3,0x15,0x07,0x33, - 0x4d,0x0c,0x05,0x65,0x90,0x81,0x19,0x0e,0x13,0x02,0xf9,0x8c,0x57,0x2c,0xd0,0x75, - 0x21,0x14,0x94,0x41,0x06,0xe8,0x60,0x4c,0x08,0xe4,0x63,0x41,0x01,0x9f,0xf1,0x0a, - 0xa8,0xe2,0x38,0x86,0x82,0x62,0x43,0x00,0x9f,0xd9,0x06,0xa7,0x02,0x66,0x1b,0x82, - 0x2a,0x98,0x6d,0x08,0x06,0x21,0x83,0x80,0x18,0x00,0x00,0x00,0x04,0x00,0x00,0x00, - 0x5b,0x86,0x20,0xc8,0x83,0x2d,0x43,0x11,0xe4,0xc1,0x96,0x41,0x09,0xf2,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sspine_fs_bytecode_metal_ios[3241] = { - 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xa9,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xd0,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, - 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, - 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xf2,0xd8,0x54,0xd8,0x76,0x28,0x3c, - 0xc1,0x24,0xd6,0xe7,0xb5,0xc4,0xbc,0x0f,0x0f,0x5a,0x55,0xdc,0x0c,0x24,0xa5,0x96, - 0x04,0x74,0x34,0x10,0x4e,0xdf,0x2e,0x1d,0xee,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, - 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44, - 0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17,0x0b,0x00,0x00,0x00, - 0x00,0x14,0x00,0x00,0x00,0xbc,0x0b,0x00,0x00,0xff,0xff,0xff,0xff,0x42,0x43,0xc0, - 0xde,0x21,0x0c,0x00,0x00,0xec,0x02,0x00,0x00,0x0b,0x82,0x20,0x00,0x02,0x00,0x00, - 0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04,0x49,0x06,0x10,0x32, - 0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b,0x62,0x80,0x14,0x45, - 0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18,0x49,0x0a,0x32,0x44, - 0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21,0x72,0x24,0x07,0xc8, - 0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00,0x00,0x51,0x18,0x00, - 0x00,0x8e,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff,0xff,0x01,0x60,0x00, - 0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07,0x7a,0x60,0x87,0x7c, - 0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72,0x68,0x03,0x72,0x48, - 0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90,0x07,0x7a,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc,0x21,0x1c,0xd8,0x61, - 0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81,0x1d,0xca,0xa1,0x0d, - 0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d,0xd8,0x61,0x1e,0x00, - 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87,0x79,0x98,0x87,0x36, - 0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36,0x30,0x07,0x78,0x68, - 0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0xc2,0x1d,0xde, - 0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0,0xe1,0x1d,0xd2,0xc1, - 0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1,0x1d,0x00,0x7a,0x90, - 0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90,0x87,0x70,0x68,0x87, - 0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07,0x79,0x68,0x83,0x72, - 0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36,0x60,0x87,0x72,0x08, - 0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30,0x87,0x79,0x68,0x03, - 0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1, - 0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01,0x1e,0xda,0x80,0x1e, - 0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07, - 0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87,0x36,0x30,0x07,0x78, - 0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20, - 0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c,0xc8,0xa1,0x0d,0xf4, - 0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda,0xa0,0x1d,0xc2,0x81, - 0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0xa0, - 0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68,0x83,0x76,0x08,0x07, - 0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6,0x81,0x1e,0xc2,0x61, - 0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61,0x1c,0xe8,0xe1,0x1d, - 0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e,0xda,0x60,0x1e,0xd2, - 0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87,0x70,0x30,0x87,0x72, - 0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e, - 0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e,0xde,0xc1,0x1c,0xe8, - 0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87,0x70,0x60,0x87,0x79, - 0x28,0x07,0x60,0x03,0x22,0x0c,0x40,0x02,0x2c,0x40,0xb5,0xc1,0x18,0x08,0x60,0x01, - 0xaa,0x0d,0x06,0x51,0x00,0x0b,0x50,0x6d,0x30,0x8a,0xff,0xff,0xff,0xff,0x1f,0x00, - 0x09,0xa0,0x36,0x20,0xc6,0xff,0xff,0xff,0xff,0x0f,0x00,0x03,0x48,0x40,0xb5,0xc1, - 0x38,0x02,0x60,0x01,0xaa,0x0d,0x06,0x22,0x00,0x0b,0x50,0x01,0x00,0x49,0x18,0x00, - 0x00,0x03,0x00,0x00,0x00,0x13,0x88,0x40,0x18,0x88,0x09,0x41,0x31,0x61,0x30,0x0e, - 0x04,0x89,0x20,0x00,0x00,0x27,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, - 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, - 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x6c,0x33,0x00,0xc3,0x08,0x04,0x60,0x83,0x30,0x8c, - 0x20,0x00,0x07,0x49,0x53,0x44,0x09,0x93,0x5f,0x48,0xff,0x03,0x44,0x00,0x23,0xa1, - 0x00,0x0c,0x22,0x10,0xc2,0x51,0xd2,0x14,0x51,0xc2,0xe4,0xff,0x13,0x71,0x4d,0x54, - 0x44,0xfc,0xf6,0xf0,0x4f,0x63,0x04,0xc0,0x20,0x82,0x11,0x5c,0x24,0x4d,0x11,0x25, - 0x4c,0xfe,0x2f,0x01,0xcc,0xb3,0x10,0xd1,0x3f,0x8d,0x11,0x00,0x83,0x08,0x88,0x50, - 0x0c,0x31,0x42,0x39,0x89,0x54,0x21,0x42,0x08,0x81,0xd8,0x1c,0x41,0x30,0x47,0x00, - 0x06,0xc3,0x08,0xc2,0x53,0x90,0x70,0xd2,0x70,0xd0,0x01,0x8a,0x03,0x01,0x29,0xf0, - 0x86,0x11,0x86,0x67,0x18,0x61,0x00,0x86,0x11,0x88,0x67,0x8e,0x00,0x14,0x06,0x11, - 0x00,0x61,0x04,0x00,0x00,0x13,0xa8,0x70,0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83, - 0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37, - 0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80, - 0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06, - 0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9, - 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60, - 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07, - 0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74, - 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0, - 0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07, - 0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73, - 0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40, - 0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, - 0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78, - 0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10, - 0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07, - 0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6, - 0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60, - 0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07, - 0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71, - 0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80, - 0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20,0x07,0x43,0x98,0x05,0x00,0x80,0x00, - 0x00,0x00,0x00,0x00,0x80,0x21,0x4c,0x03,0x04,0x80,0x00,0x00,0x00,0x00,0x00,0xc0, - 0x10,0x46,0x02,0x02,0x60,0x00,0x00,0x00,0x00,0x00,0x20,0x0b,0x04,0x09,0x00,0x00, - 0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43, - 0x7a,0x23,0x00,0x25,0x50,0x08,0x45,0x50,0x10,0x65,0x40,0x78,0x04,0x80,0xe8,0x58, - 0x02,0x24,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xf9,0x00,0x00,0x00,0x1a,0x03,0x4c, - 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x63, - 0x4c,0x00,0xa5,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, - 0x3c,0xc4,0x24,0x3c,0x05,0xe7,0x20,0x08,0x0e,0x8e,0xad,0x0c,0xa4,0xad,0x8c,0x2e, - 0x8c,0x0d,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x06,0x06,0x26,0xc6, - 0xc5,0xc6,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x06, - 0x06,0x26,0xc6,0xc5,0xc6,0xe6,0xc6,0x45,0x26,0x65,0x88,0x30,0x11,0x43,0x8c,0x87, - 0x78,0x8e,0x67,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x99,0x8e,0x87,0x78,0x88, - 0x67,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, - 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x98, - 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, - 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84, - 0x69,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, - 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, - 0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d,0x11,0xa6,0x86,0x51,0x58,0x9a,0x9c,0x8b, - 0x5c,0x99,0x1b,0x59,0x99,0xdc,0x17,0x5d,0x98,0xdc,0x59,0x19,0x1d,0xa3,0xb0,0x34, - 0x39,0x97,0x30,0xb9,0xb3,0x2f,0xba,0x3c,0xb8,0xb2,0x2f,0xb7,0xb0,0xb6,0x32,0x1a, - 0x66,0x6c,0x6f,0x61,0x74,0x34,0x64,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xdc, - 0xc2,0xda,0xca,0xa8,0x98,0xc9,0x85,0x9d,0x7d,0x8d,0xbd,0xb1,0xbd,0xc9,0x0d,0x61, - 0xa6,0xe7,0x19,0x26,0x68,0x8a,0x26,0x69,0x9a,0x86,0x08,0x13,0x45,0x29,0x2c,0x4d, - 0xce,0xc5,0x4c,0x2e,0xec,0xac,0xad,0xcc,0x8d,0xee,0x2b,0xcd,0x0d,0xae,0x8e,0x8e, - 0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x1b,0x4c,0x0a,0x95,0xb0,0x34,0x39, - 0x97,0xb1,0x32,0x37,0xba,0x32,0x39,0x3e,0x61,0x69,0x72,0x2e,0x70,0x65,0x72,0x73, - 0x70,0x65,0x63,0x74,0x69,0x76,0x65,0x34,0xcc,0xd8,0xde,0xc2,0xe8,0x64,0x28,0xd4, - 0xd9,0x0d,0x91,0x9e,0x61,0xb2,0xa6,0x6b,0xc2,0xa6,0x6c,0x82,0x26,0x6d,0x92,0xa6, - 0x8d,0x4b,0xdd,0x5c,0x99,0x1c,0x0a,0xdb,0xdb,0x98,0x5b,0x4c,0x0a,0x8b,0xb1,0x37, - 0xb6,0x37,0xb9,0x21,0xd2,0x43,0x4c,0xd6,0xd4,0x4d,0xd8,0x94,0x4d,0xd0,0x14,0x4d, - 0xd2,0xe4,0x51,0x09,0x4b,0x93,0x73,0x11,0xab,0x33,0x33,0x2b,0x93,0xe3,0x13,0x96, - 0x26,0xe7,0x22,0x56,0x67,0x66,0x56,0x26,0xf7,0x35,0x97,0xa6,0x57,0x46,0x29,0x2c, - 0x4d,0xce,0x85,0xed,0x6d,0x2c,0x8c,0x2e,0xed,0xcd,0xed,0x2b,0xcd,0x8d,0xac,0x0c, - 0x8f,0x48,0x58,0x9a,0x9c,0x8b,0x5c,0x59,0x18,0x19,0xa9,0xb0,0x34,0x39,0x97,0x39, - 0x3a,0xb9,0xba,0x31,0xba,0x2f,0xba,0x3c,0xb8,0xb2,0xaf,0x34,0x37,0xb3,0x37,0x16, - 0x66,0x6c,0x6f,0x61,0x74,0x1c,0xe0,0xda,0xc2,0x86,0x28,0xcf,0xf0,0x14,0xcf,0x30, - 0x95,0xc1,0x64,0x06,0x8c,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0, - 0xca,0xbe,0xe6,0xd2,0xf4,0xca,0x78,0x85,0xa5,0xc9,0xb9,0x84,0xc9,0x9d,0x7d,0xd1, - 0xe5,0xc1,0x95,0x7d,0x85,0xb1,0xa5,0x9d,0xb9,0x7d,0xcd,0xa5,0xe9,0x95,0x31,0x31, - 0x9b,0xfb,0x82,0x0b,0x93,0x0b,0x6b,0x9b,0xe3,0xf0,0x55,0x33,0x33,0x84,0x0c,0x1e, - 0x63,0x02,0x83,0x29,0x0c,0x9e,0x62,0x12,0x83,0x67,0x78,0x88,0x69,0x0c,0x26,0x32, - 0x98,0xce,0x60,0x42,0x83,0xa7,0x98,0xd2,0xe0,0x29,0x26,0x68,0x52,0x83,0x49,0x9a, - 0xd6,0x80,0x4b,0x58,0x9a,0x9c,0x0b,0x5d,0x19,0x1e,0x5d,0x9d,0x5c,0x19,0x95,0xb0, - 0x34,0x39,0x97,0xb9,0xb0,0x36,0x38,0xb6,0x32,0x62,0x74,0x65,0x78,0x74,0x75,0x72, - 0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c, - 0x65,0x3e,0x1c,0xe8,0xca,0xf0,0x86,0x50,0x0f,0x32,0xb5,0xc1,0x24,0x06,0xcf,0xf0, - 0x10,0x93,0x1b,0x4c,0xd0,0xf4,0x06,0x93,0x34,0xc1,0x01,0x97,0xb0,0x34,0x39,0x97, - 0xb9,0xb0,0x36,0x38,0xb6,0x32,0x39,0x1e,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x1c, - 0xe6,0xda,0xe0,0x86,0x48,0x4f,0x31,0xc9,0xc1,0x24,0x06,0xcf,0xf0,0x10,0x13,0x34, - 0xcd,0xc1,0x24,0x4d,0x74,0x30,0x44,0x99,0xb8,0xe9,0x9b,0xd8,0x60,0x8a,0x83,0xa9, - 0x0e,0x86,0x18,0x0b,0x30,0x55,0x93,0x1d,0xd0,0xf9,0xd2,0xa2,0x9a,0xca,0x31,0x9b, - 0xfb,0x82,0x0b,0x93,0x0b,0x6b,0x9b,0xe3,0xf3,0xd6,0xe6,0x96,0x06,0xf7,0x46,0x57, - 0xe6,0x46,0x07,0x32,0x86,0x16,0x26,0xc7,0x67,0x2a,0xad,0x0d,0x8e,0xad,0x0c,0x64, - 0x68,0x65,0x05,0x84,0x4a,0x28,0x28,0x68,0x88,0x30,0xe9,0xc1,0x10,0x63,0xca,0x83, - 0x69,0x0f,0xb0,0x64,0x88,0x31,0x95,0xc1,0xc4,0x07,0x58,0x32,0xc4,0x98,0xf0,0x60, - 0xea,0x03,0x2c,0x19,0x62,0x4c,0x7e,0x30,0xf5,0x01,0x96,0x8c,0x88,0xd8,0x81,0x1d, - 0xec,0xa1,0x1d,0xdc,0xa0,0x1d,0xde,0x81,0x1c,0xea,0x81,0x1d,0xca,0xc1,0x0d,0xcc, - 0x81,0x1d,0xc2,0xe1,0x1c,0xe6,0x61,0x8a,0x10,0x0c,0x23,0x14,0x76,0x60,0x07,0x7b, - 0x68,0x07,0x37,0x48,0x07,0x72,0x28,0x07,0x77,0xa0,0x87,0x29,0x41,0x31,0x62,0x09, - 0x87,0x74,0x90,0x07,0x37,0xb0,0x87,0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87, - 0x29,0x81,0x31,0x82,0x0a,0x87,0x74,0x90,0x07,0x37,0x60,0x87,0x70,0x70,0x87,0x73, - 0xa8,0x87,0x70,0x38,0x87,0x72,0xf8,0x05,0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78, - 0x07,0x77,0x98,0x12,0x20,0x23,0xa6,0x70,0x48,0x07,0x79,0x70,0x83,0x71,0x78,0x87, - 0x76,0x80,0x87,0x74,0x60,0x87,0x72,0xf8,0x85,0x77,0x80,0x07,0x7a,0x48,0x87,0x77, - 0x70,0x87,0x79,0x98,0x32,0x28,0x8c,0x33,0x82,0x09,0x87,0x74,0x90,0x07,0x37,0x30, - 0x07,0x79,0x08,0x87,0x73,0x68,0x87,0x72,0x70,0x07,0x7a,0x98,0x12,0xdc,0x01,0x00, - 0x00,0x79,0x18,0x00,0x00,0x7b,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, - 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, - 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, - 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, - 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, - 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, - 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, - 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, - 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, - 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, - 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, - 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, - 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, - 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, - 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, - 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, - 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, - 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, - 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, - 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, - 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, - 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, - 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, - 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, - 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, - 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, - 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, - 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x98,0x81,0x5c,0xe3,0x10,0x0e,0xec, - 0xc0,0x0e,0xe5,0x50,0x0e,0xf3,0x30,0x23,0xc1,0xd2,0x41,0x1e,0xe4,0xe1,0x17,0xd8, - 0xe1,0x1d,0xde,0x01,0x1e,0x66,0x50,0x59,0x38,0xa4,0x83,0x3c,0xb8,0x81,0x39,0xd4, - 0x83,0x3b,0x8c,0x03,0x3d,0xa4,0xc3,0x3b,0xb8,0xc3,0x2f,0x9c,0x83,0x3c,0xbc,0x43, - 0x3d,0xc0,0xc3,0x3c,0x00,0x71,0x20,0x00,0x00,0x0b,0x00,0x00,0x00,0x26,0xb0,0x01, - 0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e, - 0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x6d,0x01,0x0d,0x80,0x44,0x3e,0x83, - 0x5c,0x7e,0x85,0x17,0xb7,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x25,0x00,0x00, - 0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x74,0x47,0x00, - 0xc6,0x22,0x80,0x40,0x38,0xe6,0x20,0x06,0xc2,0xa8,0xc8,0xd5,0xc0,0x08,0x00,0xbd, - 0x19,0x00,0x82,0x23,0x00,0x54,0xc7,0x1a,0x80,0x40,0x18,0x6b,0x18,0x86,0x81,0xec, - 0x0c,0x00,0x89,0x19,0x00,0x0a,0x33,0x00,0x04,0x46,0x00,0x00,0x00,0x23,0x06,0xca, - 0x10,0x6c,0x8f,0x23,0x29,0x47,0x12,0x58,0x20,0xc9,0x67,0x90,0x21,0x20,0x90,0x41, - 0x06,0xa1,0x40,0x4c,0x08,0xe4,0x33,0xc8,0x10,0x24,0xd0,0x20,0x43,0x50,0x48,0x16, - 0x60,0xf2,0x19,0x6f,0xc0,0x38,0x31,0xa0,0x60,0xcc,0x31,0x30,0x01,0x19,0x0c,0x32, - 0x04,0x0d,0x36,0x62,0x60,0x08,0x01,0x1a,0x2c,0x45,0x30,0xdb,0x00,0x05,0x40,0x06, - 0x01,0x31,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x5b,0x86,0x24,0xf8,0x03,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -static const uint8_t _sspine_vs_source_metal_sim[624] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x6d,0x76,0x70,0x3b,0x0a,0x7d,0x3b,0x0a, - 0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75, - 0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x75, - 0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d, - 0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31, - 0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70,0x6f, - 0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74, - 0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a, - 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x70,0x6f,0x73,0x69,0x74, - 0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28, - 0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32, - 0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74, - 0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20, - 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x5b, - 0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x32,0x29,0x5d,0x5d,0x3b, - 0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74,0x65,0x78,0x20,0x6d,0x61,0x69,0x6e, - 0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e, - 0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f, - 0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x26,0x20,0x5f,0x31,0x39,0x20,0x5b,0x5b, - 0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20, - 0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74, - 0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67, - 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x5f,0x31,0x39, - 0x2e,0x6d,0x76,0x70,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x69,0x6e, - 0x2e,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x75,0x76, - 0x20,0x3d,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b, - 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, - 0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20, - 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, - -}; -static const uint8_t _sspine_fs_source_metal_sim[619] = { - 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, - 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, - 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, - 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, - 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x66, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x20,0x70,0x6d,0x61,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74, - 0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b, - 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67, - 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30, - 0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, - 0x6c,0x6f,0x61,0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28, - 0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65, - 0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a, - 0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, - 0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, - 0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d, - 0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x66,0x73,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x73,0x26,0x20,0x5f,0x35,0x33,0x20,0x5b,0x5b,0x62,0x75,0x66, - 0x66,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78,0x74,0x75,0x72, - 0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65,0x78,0x20,0x5b, - 0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d,0x2c,0x20,0x73, - 0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x6d,0x70,0x20,0x5b,0x5b,0x73,0x61,0x6d, - 0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20, - 0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d, - 0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, - 0x5f,0x32,0x38,0x20,0x3d,0x20,0x74,0x65,0x78,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65, - 0x28,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e,0x2e,0x75,0x76,0x29,0x20,0x2a,0x20,0x69, - 0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, - 0x61,0x74,0x20,0x5f,0x33,0x37,0x20,0x3d,0x20,0x5f,0x32,0x38,0x2e,0x77,0x3b,0x0a, - 0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x6d,0x69,0x78,0x28,0x5f,0x32,0x38,0x2c,0x20,0x66,0x6c, - 0x6f,0x61,0x74,0x34,0x28,0x5f,0x32,0x38,0x2e,0x78,0x79,0x7a,0x20,0x2a,0x20,0x5f, - 0x33,0x37,0x2c,0x20,0x5f,0x33,0x37,0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f, - 0x6c,0x6f,0x72,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x5f,0x35,0x33,0x2e, - 0x70,0x6d,0x61,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72, - 0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_WGPU) -static const uint8_t _sspine_vs_source_wgsl[1003] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x6d,0x76,0x70,0x20,0x3a,0x20,0x6d,0x61,0x74,0x34,0x78,0x34,0x66,0x2c,0x0a, - 0x7d,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x30,0x29,0x20,0x40,0x62,0x69, - 0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20,0x76,0x61,0x72,0x3c,0x75,0x6e,0x69, - 0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x31,0x39,0x20,0x3a,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, - 0x76,0x61,0x74,0x65,0x3e,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70, - 0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74, - 0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a, - 0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20, - 0x7b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x32,0x20,0x3a,0x20,0x6d, - 0x61,0x74,0x34,0x78,0x34,0x66,0x20,0x3d,0x20,0x78,0x5f,0x31,0x39,0x2e,0x6d,0x76, - 0x70,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x36,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x5f,0x31,0x3b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x20,0x3d,0x20,0x28,0x78,0x5f,0x32,0x32,0x20,0x2a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x28,0x78,0x5f,0x32,0x36,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32,0x36,0x2e,0x79, - 0x2c,0x20,0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x29,0x3b,0x0a, - 0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x38,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a, - 0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x78,0x5f,0x33,0x38,0x3b,0x0a,0x20,0x20,0x6c, - 0x65,0x74,0x20,0x78,0x5f,0x34,0x32,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3d,0x20,0x78,0x5f,0x34,0x32,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75, - 0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61, - 0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c, - 0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20, - 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x34,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, - 0x28,0x30,0x29,0x0a,0x20,0x20,0x75,0x76,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x31,0x29,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78, - 0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x28,0x30,0x29,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x74,0x65,0x78, - 0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x32,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e, - 0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x5f,0x31,0x20,0x3d,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x31, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, - 0x72,0x64,0x30,0x20,0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, - 0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65, - 0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c, - 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63, - 0x6f,0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -static const uint8_t _sspine_fs_source_wgsl[1125] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a, - 0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20, - 0x20,0x70,0x6d,0x61,0x20,0x3a,0x20,0x66,0x33,0x32,0x2c,0x0a,0x7d,0x0a,0x0a,0x40, - 0x67,0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e, - 0x67,0x28,0x34,0x38,0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20, - 0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b, - 0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e, - 0x64,0x69,0x6e,0x67,0x28,0x36,0x34,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70, - 0x20,0x3a,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72, - 0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76, - 0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e, - 0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65, - 0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x30,0x29,0x20, - 0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x34,0x29,0x20,0x76,0x61,0x72,0x3c, - 0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x35,0x33,0x20,0x3a,0x20, - 0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d, - 0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20,0x76,0x61,0x72,0x20, - 0x63,0x30,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x20,0x20,0x76,0x61, - 0x72,0x20,0x63,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x20,0x20, - 0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32, - 0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, - 0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x73, - 0x6d,0x70,0x2c,0x20,0x78,0x5f,0x32,0x33,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x32,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x63,0x30,0x20,0x3d,0x20,0x28,0x78, - 0x5f,0x32,0x34,0x20,0x2a,0x20,0x78,0x5f,0x32,0x37,0x29,0x3b,0x0a,0x20,0x20,0x6c, - 0x65,0x74,0x20,0x78,0x5f,0x33,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20, - 0x3d,0x20,0x63,0x30,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x37, - 0x20,0x3a,0x20,0x66,0x33,0x32,0x20,0x3d,0x20,0x63,0x30,0x2e,0x77,0x3b,0x0a,0x20, - 0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x38,0x20,0x3a,0x20,0x76,0x65,0x63,0x33, - 0x66,0x20,0x3d,0x20,0x28,0x76,0x65,0x63,0x33,0x66,0x28,0x78,0x5f,0x33,0x31,0x2e, - 0x78,0x2c,0x20,0x78,0x5f,0x33,0x31,0x2e,0x79,0x2c,0x20,0x78,0x5f,0x33,0x31,0x2e, - 0x7a,0x29,0x20,0x2a,0x20,0x78,0x5f,0x33,0x37,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65, - 0x74,0x20,0x78,0x5f,0x34,0x30,0x20,0x3a,0x20,0x66,0x33,0x32,0x20,0x3d,0x20,0x63, - 0x30,0x2e,0x77,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x35,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b, - 0x0a,0x20,0x20,0x63,0x31,0x20,0x3d,0x20,0x28,0x76,0x65,0x63,0x34,0x66,0x28,0x78, - 0x5f,0x33,0x38,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x33,0x38,0x2e,0x79,0x2c,0x20,0x78, - 0x5f,0x33,0x38,0x2e,0x7a,0x2c,0x20,0x78,0x5f,0x34,0x30,0x29,0x20,0x2a,0x20,0x78, - 0x5f,0x34,0x35,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x34,0x39, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63,0x30,0x3b,0x0a,0x20, - 0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x35,0x30,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, - 0x66,0x20,0x3d,0x20,0x63,0x31,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f, - 0x35,0x38,0x20,0x3a,0x20,0x66,0x33,0x32,0x20,0x3d,0x20,0x78,0x5f,0x35,0x33,0x2e, - 0x70,0x6d,0x61,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3d,0x20,0x6d,0x69,0x78,0x28,0x78,0x5f,0x34,0x39,0x2c,0x20,0x78,0x5f, - 0x35,0x30,0x2c,0x20,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x35,0x38,0x2c,0x20, - 0x78,0x5f,0x35,0x38,0x2c,0x20,0x78,0x5f,0x35,0x38,0x2c,0x20,0x78,0x5f,0x35,0x38, - 0x29,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a, - 0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74, - 0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30, - 0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x66,0x72, - 0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40, - 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20,0x75,0x76,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20, - 0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20, - 0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x70, - 0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29, - 0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f, - 0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x29,0x3b, - 0x0a,0x7d,0x0a,0x0a,0x00, -}; -#elif defined(SOKOL_DUMMY_BACKEND) -static const char* _sspine_vs_source_dummy = ""; -static const char* _sspine_fs_source_dummy = ""; -#else -#error "Please define one of SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" -#endif - -// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██████ ██ ██ ██ ██ ███████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██████ ██████ ██ ███████ -// -// >>structs - -#define _sspine_def(val, def) (((val) == 0) ? (def) : (val)) -#define _SSPINE_INIT_COOKIE (0xABBAABBA) -#define _SSPINE_INVALID_SLOT_INDEX (0) -#define _SSPINE_DEFAULT_CONTEXT_POOL_SIZE (4) -#define _SSPINE_DEFAULT_ATLAS_POOL_SIZE (64) -#define _SSPINE_DEFAULT_SKELETON_POOL_SIZE (64) -#define _SSPINE_DEFAULT_SKINSET_POOL_SIZE (64) -#define _SSPINE_DEFAULT_INSTANCE_POOL_SIZE (1024) -#define _SSPINE_DEFAULT_MAX_VERTICES (1<<16) -#define _SSPINE_DEFAULT_MAX_COMMANDS (1<<14) -#define _SSPINE_MAX_TRIGGERED_EVENTS (16) -#define _SSPINE_SLOT_SHIFT (16) -#define _SSPINE_MAX_POOL_SIZE (1<<_SSPINE_SLOT_SHIFT) -#define _SSPINE_SLOT_MASK (_SSPINE_MAX_POOL_SIZE-1) - -typedef struct { - float mvp[16]; -} _sspine_vsparams_t; - -typedef struct { - float pma; - uint8_t _pad[12]; -} _sspine_fsparams_t; - -typedef struct { - uint32_t id; - sspine_resource_state state; -} _sspine_slot_t; - -typedef struct { - int size; - int queue_top; - uint32_t* gen_ctrs; - int* free_queue; -} _sspine_pool_t; - -typedef struct { - _sspine_slot_t slot; - sspine_atlas_overrides overrides; - spAtlas* sp_atlas; - int num_pages; -} _sspine_atlas_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_atlas_t* items; -} _sspine_atlas_pool_t; - -typedef struct { - uint32_t id; - _sspine_atlas_t* ptr; -} _sspine_atlas_ref_t; - -typedef struct { - sg_image img; - sg_sampler smp; -} _sspine_image_sampler_pair_t; - -typedef struct { - _sspine_slot_t slot; - _sspine_atlas_ref_t atlas; - spSkeletonData* sp_skel_data; - spAnimationStateData* sp_anim_data; - struct { - int cap; - sspine_vec2* ptr; - } tform_buf; -} _sspine_skeleton_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_skeleton_t* items; -} _sspine_skeleton_pool_t; - -typedef struct { - uint32_t id; - _sspine_skeleton_t* ptr; -} _sspine_skeleton_ref_t; - -typedef struct { - _sspine_slot_t slot; - _sspine_skeleton_ref_t skel; - spSkin* sp_skin; -} _sspine_skinset_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_skinset_t* items; -} _sspine_skinset_pool_t; - -typedef struct { - uint32_t id; - _sspine_skinset_t* ptr; -} _sspine_skinset_ref_t; - -typedef struct { - _sspine_slot_t slot; - _sspine_atlas_ref_t atlas; - _sspine_skeleton_ref_t skel; - _sspine_skinset_ref_t skinset; - spSkeleton* sp_skel; - spAnimationState* sp_anim_state; - spSkeletonClipping* sp_clip; - int cur_triggered_event_index; - sspine_triggered_event_info triggered_events[_SSPINE_MAX_TRIGGERED_EVENTS]; -} _sspine_instance_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_instance_t* items; -} _sspine_instance_pool_t; - -typedef struct { - sspine_vec2 pos; - sspine_vec2 uv; - uint32_t color; -} _sspine_vertex_t; - -typedef struct { - _sspine_vertex_t* ptr; - int index; -} _sspine_alloc_vertices_result_t; - -typedef struct { - uint32_t* ptr; - int index; -} _sspine_alloc_indices_result_t; - -typedef struct { - int layer; - sg_pipeline pip; - sg_image img; - sg_sampler smp; - float pma; // pma = 0.0: use texture color as is, pma = 1.0: multiply texture rgb by texture alpha in fragment shader - int base_element; - int num_elements; -} _sspine_command_t; - -typedef struct { - _sspine_slot_t slot; - float transform[16]; - struct { - int cap; - int next; - uint32_t rewind_frame_id; - _sspine_vertex_t* ptr; - } vertices; - struct { - int cap; - int next; - uint32_t rewind_frame_id; - uint32_t* ptr; - } indices; - struct { - int cap; - int next; - uint32_t rewind_frame_id; - _sspine_command_t* ptr; - } commands; - uint32_t update_frame_id; - sg_buffer vbuf; - sg_buffer ibuf; - struct { - sg_pipeline normal_additive; - sg_pipeline multiply; - } pip; - sg_bindings bind; -} _sspine_context_t; - -typedef struct { - _sspine_pool_t pool; - _sspine_context_t* items; -} _sspine_context_pool_t; - -typedef struct { - uint32_t init_cookie; - uint32_t frame_id; - sspine_desc desc; - sspine_context def_ctx_id; - sspine_context cur_ctx_id; - _sspine_context_t* cur_ctx; // may be 0! - sg_shader shd; - _sspine_context_pool_t context_pool; - _sspine_atlas_pool_t atlas_pool; - _sspine_skeleton_pool_t skeleton_pool; - _sspine_skinset_pool_t skinset_pool; - _sspine_instance_pool_t instance_pool; -} _sspine_t; -static _sspine_t _sspine; - -// dummy spine-c platform implementation functions -#if defined(__cplusplus) -extern "C" { -#endif -void _spAtlasPage_createTexture(spAtlasPage* self, const char* path) { - // nothing to do here - (void)self; (void)path; -} - -static void _sspine_delete_image_sampler_pair(const _sspine_image_sampler_pair_t* isp); -void _spAtlasPage_disposeTexture(spAtlasPage* self) { - _sspine_delete_image_sampler_pair((const _sspine_image_sampler_pair_t*) self->rendererObject); -} - -char* _spUtil_readFile(const char* path, int* length) { - (void)path; - *length = 0; - return 0; -} -#if defined(__cplusplus) -} // extern "C" -#endif - -// ██ ██████ ██████ ██████ ██ ███ ██ ██████ -// ██ ██ ██ ██ ██ ██ ████ ██ ██ -// ██ ██ ██ ██ ███ ██ ███ ██ ██ ██ ██ ██ ███ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██████ ██████ ██████ ██ ██ ████ ██████ -// -// >>logging -#if defined(SOKOL_DEBUG) -#define _SSPINE_LOGITEM_XMACRO(item,msg) #item ": " msg, -static const char* _sspine_log_messages[] = { - _SSPINE_LOG_ITEMS -}; -#undef _SSPINE_LOGITEM_XMACRO -#endif // SOKOL_DEBUG - -#define _SSPINE_PANIC(code) _sspine_log(SSPINE_LOGITEM_ ##code, 0, __LINE__) -#define _SSPINE_ERROR(code) _sspine_log(SSPINE_LOGITEM_ ##code, 1, __LINE__) -#define _SSPINE_WARN(code) _sspine_log(SSPINE_LOGITEM_ ##code, 2, __LINE__) -#define _SSPINE_INFO(code) _sspine_log(SSPINE_LOGITEM_ ##code, 3, __LINE__) - -static void _sspine_log(sspine_log_item log_item, uint32_t log_level, uint32_t line_nr) { - if (_sspine.desc.logger.func) { - #if defined(SOKOL_DEBUG) - const char* filename = __FILE__; - const char* message = _sspine_log_messages[log_item]; - #else - const char* filename = 0; - const char* message = 0; - #endif - _sspine.desc.logger.func("sspine", log_level, log_item, message, line_nr, filename, _sspine.desc.logger.user_data); - } else { - // for log level PANIC it would be 'undefined behaviour' to continue - if (log_level == 0) { - abort(); - } - } -} - -// ███ ███ ███████ ███ ███ ██████ ██████ ██ ██ -// ████ ████ ██ ████ ████ ██ ██ ██ ██ ██ ██ -// ██ ████ ██ █████ ██ ████ ██ ██ ██ ██████ ████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ██ ██████ ██ ██ ██ -// -// >>memory -static void _sspine_clear(void* ptr, size_t size) { - SOKOL_ASSERT(ptr && (size > 0)); - memset(ptr, 0, size); -} - -/* Copy a string into a fixed size buffer with guaranteed zero- - termination. - - Return false if the string didn't fit into the buffer and had to be clamped. - - FIXME: Currently UTF-8 strings might become invalid if the string - is clamped, because the last zero-byte might be written into - the middle of a multi-byte sequence. -*/ -static bool _sspine_strcpy(const char* src, char* dst, int max_len) { - SOKOL_ASSERT(src && dst && (max_len > 0)); - char* const end = &(dst[max_len-1]); - char c = 0; - for (int i = 0; i < max_len; i++) { - c = *src; - if (c != 0) { - src++; - } - *dst++ = c; - } - // truncated? - if (c != 0) { - *end = 0; - return false; - } else { - return true; - } -} - -static sspine_string _sspine_string(const char* cstr) { - sspine_string res; - _sspine_clear(&res, sizeof(res)); - if (cstr) { - res.valid = true; - res.truncated = !_sspine_strcpy(cstr, res.cstr, sizeof(res.cstr)); - res.len = (uint8_t)strlen(res.cstr); - } - return res; -} - -static void* _sspine_malloc(size_t size) { - SOKOL_ASSERT(size > 0); - void* ptr; - if (_sspine.desc.allocator.alloc_fn) { - ptr = _sspine.desc.allocator.alloc_fn(size, _sspine.desc.allocator.user_data); - } else { - ptr = malloc(size); - } - if (0 == ptr) { - _SSPINE_PANIC(MALLOC_FAILED); - } - return ptr; -} - -static void* _sspine_malloc_clear(size_t size) { - void* ptr = _sspine_malloc(size); - _sspine_clear(ptr, size); - return ptr; -} - -static void _sspine_free(void* ptr) { - if (_sspine.desc.allocator.free_fn) { - _sspine.desc.allocator.free_fn(ptr, _sspine.desc.allocator.user_data); - } else { - free(ptr); - } -} - -// ██████ ███████ ███████ ███████ -// ██ ██ ██ ██ ██ -// ██████ █████ █████ ███████ -// ██ ██ ██ ██ ██ -// ██ ██ ███████ ██ ███████ -// -// >>refs -static bool _sspine_atlas_ref_valid(const _sspine_atlas_ref_t* ref) { - return ref->ptr && (ref->ptr->slot.id == ref->id); -} - -static bool _sspine_skeleton_ref_valid(const _sspine_skeleton_ref_t* ref) { - return ref->ptr && (ref->ptr->slot.id == ref->id); -} - -static bool _sspine_skinset_ref_valid(const _sspine_skinset_ref_t* ref) { - return ref->ptr && (ref->ptr->slot.id == ref->id); -} - -static bool _sspine_skeleton_and_deps_valid(_sspine_skeleton_t* skeleton) { - return skeleton && _sspine_atlas_ref_valid(&skeleton->atlas); -} - -static bool _sspine_skinset_and_deps_valid(_sspine_skinset_t* skinset) { - return skinset && _sspine_skeleton_ref_valid(&skinset->skel); -} - -static bool _sspine_instance_and_deps_valid(_sspine_instance_t* instance) { - return instance && - _sspine_atlas_ref_valid(&instance->atlas) && - _sspine_skeleton_ref_valid(&instance->skel) && - ((instance->skinset.id == SSPINE_INVALID_ID) || _sspine_skinset_ref_valid(&instance->skinset)); -} - -static sspine_image _sspine_image(uint32_t atlas_id, int index) { - sspine_image img = { atlas_id, index }; - return img; -} - -static sspine_atlas_page _sspine_atlas_page(uint32_t atlas_id, int index) { - sspine_atlas_page page = { atlas_id, index }; - return page; -} - -static sspine_anim _sspine_anim(uint32_t skeleton_id, int index) { - sspine_anim anim = { skeleton_id, index }; - return anim; -} - -static sspine_bone _sspine_bone(uint32_t skeleton_id, int index) { - sspine_bone bone = { skeleton_id, index }; - return bone; -} - -static sspine_slot _sspine_slot(uint32_t skeleton_id, int index) { - sspine_slot slot = { skeleton_id, index }; - return slot; -} - -static sspine_event _sspine_event(uint32_t skeleton_id, int index) { - sspine_event event = { skeleton_id, index }; - return event; -} - -static sspine_iktarget _sspine_iktarget(uint32_t skeleton_id, int index) { - sspine_iktarget iktarget = { skeleton_id, index }; - return iktarget; -} - -static sspine_skin _sspine_skin(uint32_t skeleton_id, int index) { - sspine_skin skin = { skeleton_id, index }; - return skin; -} - -// ██████ ██████ ██████ ██ -// ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ -// -// >>pool -static void _sspine_init_pool(_sspine_pool_t* pool, int num) { - SOKOL_ASSERT(pool && (num >= 1)); - // slot 0 is reserved for the 'invalid id', so bump the pool size by 1 - pool->size = num + 1; - pool->queue_top = 0; - // generation counters indexable by pool slot index, slot 0 is reserved - size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; - pool->gen_ctrs = (uint32_t*) _sspine_malloc_clear(gen_ctrs_size); - // it's not a bug to only reserve 'num' here - pool->free_queue = (int*) _sspine_malloc_clear(sizeof(int) * (size_t)num); - // never allocate the zero-th pool item since the invalid id is 0 - for (int i = pool->size-1; i >= 1; i--) { - pool->free_queue[pool->queue_top++] = i; - } -} - -static void _sspine_discard_pool(_sspine_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - _sspine_free(pool->free_queue); - pool->free_queue = 0; - SOKOL_ASSERT(pool->gen_ctrs); - _sspine_free(pool->gen_ctrs); - pool->gen_ctrs = 0; - pool->size = 0; - pool->queue_top = 0; -} - -static int _sspine_pool_alloc_index(_sspine_pool_t* pool) { - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - if (pool->queue_top > 0) { - int slot_index = pool->free_queue[--pool->queue_top]; - SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); - return slot_index; - } else { - // pool exhausted - return _SSPINE_INVALID_SLOT_INDEX; - } -} - -static void _sspine_pool_free_index(_sspine_pool_t* pool, int slot_index) { - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT(pool); - SOKOL_ASSERT(pool->free_queue); - SOKOL_ASSERT(pool->queue_top < pool->size); - #ifdef SOKOL_DEBUG - // debug check against double-free - for (int i = 0; i < pool->queue_top; i++) { - SOKOL_ASSERT(pool->free_queue[i] != slot_index); - } - #endif - pool->free_queue[pool->queue_top++] = slot_index; - SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); -} - -/* initialize a pool slot: - - bump the slot's generation counter - - create a resource id from the generation counter and slot index - - set the slot's id to this id - - set the slot's state to ALLOC - - return the handle id -*/ -static uint32_t _sspine_slot_init(_sspine_pool_t* pool, _sspine_slot_t* slot, int slot_index) { - /* FIXME: add handling for an overflowing generation counter, - for now, just overflow (another option is to disable - the slot) - */ - SOKOL_ASSERT(pool && pool->gen_ctrs); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < pool->size)); - SOKOL_ASSERT((slot->state == SSPINE_RESOURCESTATE_INITIAL) && (slot->id == SSPINE_INVALID_ID)); - uint32_t ctr = ++pool->gen_ctrs[slot_index]; - slot->id = (ctr<<_SSPINE_SLOT_SHIFT)|(slot_index & _SSPINE_SLOT_MASK); - slot->state = SSPINE_RESOURCESTATE_ALLOC; - return slot->id; -} - -// extract slot index from id -static int _sspine_slot_index(uint32_t id) { - int slot_index = (int) (id & _SSPINE_SLOT_MASK); - SOKOL_ASSERT(_SSPINE_INVALID_SLOT_INDEX != slot_index); - return slot_index; -} - -static void _sspine_init_item_pool(_sspine_pool_t* pool, int pool_size, void** items_ptr, size_t item_size_bytes) { - // NOTE: the pools will have an additional item, since slot 0 is reserved - SOKOL_ASSERT(pool && (pool->size == 0)); - SOKOL_ASSERT((pool_size > 0) && (pool_size < _SSPINE_MAX_POOL_SIZE)); - SOKOL_ASSERT(items_ptr && (*items_ptr == 0)); - SOKOL_ASSERT(item_size_bytes > 0); - _sspine_init_pool(pool, pool_size); - const size_t pool_size_bytes = item_size_bytes * (size_t)pool->size; - *items_ptr = _sspine_malloc_clear(pool_size_bytes); -} - -static void _sspine_discard_item_pool(_sspine_pool_t* pool, void** items_ptr) { - SOKOL_ASSERT(pool && (pool->size != 0)); - SOKOL_ASSERT(items_ptr && (*items_ptr != 0)); - _sspine_free(*items_ptr); *items_ptr = 0; - _sspine_discard_pool(pool); -} - -// ██████ ██████ ███ ██ ████████ ███████ ██ ██ ████████ -// ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ █████ ███ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██████ ██ ████ ██ ███████ ██ ██ ██ -// -// >>context -static void _sspine_setup_context_pool(int pool_size) { - _sspine_context_pool_t* p = &_sspine.context_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_context_t)); -} - -static void _sspine_discard_context_pool(void) { - _sspine_context_pool_t* p = &_sspine.context_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_context _sspine_make_context_handle(uint32_t id) { - sspine_context handle = { id }; - return handle; -} - -static _sspine_context_t* _sspine_context_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_context_pool_t* p = &_sspine.context_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_context_t* _sspine_lookup_context(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_context_t* ctx = _sspine_context_at(id); - if (ctx->slot.id == id) { - return ctx; - } - } - return 0; -} - -static sspine_context _sspine_alloc_context(void) { - _sspine_context_pool_t* p = &_sspine.context_pool; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _sspine_make_context_handle(id); - } else { - // pool exhausted - return _sspine_make_context_handle(SSPINE_INVALID_ID); - } -} - -static sspine_resource_state _sspine_init_context(_sspine_context_t* ctx, const sspine_context_desc* desc) { - SOKOL_ASSERT(ctx && (ctx->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - - // setup vertex, index and command storage - ctx->vertices.cap = desc->max_vertices; - ctx->indices.cap = ctx->vertices.cap * 3; - ctx->commands.cap = desc->max_commands; - - const size_t vbuf_size = (size_t)ctx->vertices.cap * sizeof(_sspine_vertex_t); - const size_t ibuf_size = (size_t)ctx->indices.cap * sizeof(uint32_t); - const size_t cbuf_size = (size_t)ctx->commands.cap * sizeof(_sspine_command_t); - - ctx->vertices.ptr = (_sspine_vertex_t*) _sspine_malloc(vbuf_size); - ctx->indices.ptr = (uint32_t*) _sspine_malloc(ibuf_size); - ctx->commands.ptr = (_sspine_command_t*) _sspine_malloc(cbuf_size); - - sg_buffer_desc vbuf_desc; - _sspine_clear(&vbuf_desc, sizeof(vbuf_desc)); - vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER; - vbuf_desc.usage = SG_USAGE_STREAM; - vbuf_desc.size = vbuf_size; - vbuf_desc.label = "sspine-vbuf"; - ctx->vbuf = sg_make_buffer(&vbuf_desc); - ctx->bind.vertex_buffers[0] = ctx->vbuf; - - sg_buffer_desc ibuf_desc; - _sspine_clear(&ibuf_desc, sizeof(ibuf_desc)); - ibuf_desc.type = SG_BUFFERTYPE_INDEXBUFFER; - ibuf_desc.usage = SG_USAGE_STREAM; - ibuf_desc.size = ibuf_size; - ibuf_desc.label = "sspine-ibuf"; - ctx->ibuf = sg_make_buffer(&ibuf_desc); - ctx->bind.index_buffer = ctx->ibuf; - - // for blend modes, see: https://wiki.libsdl.org/SDL_BlendMode - // - // NOTE: we're configuring the blend mode for premultiplied alpha, - // and then do the premultiplication in the fragment shader - // if needed - sg_pipeline_desc pip_desc; - _sspine_clear(&pip_desc, sizeof(pip_desc)); - pip_desc.shader = _sspine.shd; - pip_desc.layout.buffers[0].stride = sizeof(_sspine_vertex_t); - pip_desc.layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT2; - pip_desc.layout.attrs[1].format = SG_VERTEXFORMAT_FLOAT2; - pip_desc.layout.attrs[2].format = SG_VERTEXFORMAT_UBYTE4N; - pip_desc.index_type = SG_INDEXTYPE_UINT32; - pip_desc.sample_count = desc->sample_count; - pip_desc.depth.pixel_format = desc->depth_format; - pip_desc.colors[0].pixel_format = desc->color_format; - pip_desc.colors[0].write_mask = desc->color_write_mask; - pip_desc.colors[0].blend.enabled = true; - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_ONE; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ONE; - pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - pip_desc.label = "sspine-pip-normal/additive"; - ctx->pip.normal_additive = sg_make_pipeline(&pip_desc); - - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_ZERO; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_SRC_COLOR; - pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ZERO; - pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE; - pip_desc.label = "sspine-pip-multiply"; - ctx->pip.multiply = sg_make_pipeline(&pip_desc); - - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_context(_sspine_context_t* ctx) { - // NOTE: it's ok to call sg_destroy functions with invalid handles - sg_destroy_pipeline(ctx->pip.normal_additive); - sg_destroy_pipeline(ctx->pip.multiply); - sg_destroy_buffer(ctx->ibuf); - sg_destroy_buffer(ctx->vbuf); - if (ctx->commands.ptr) { - _sspine_free(ctx->commands.ptr); - ctx->commands.ptr = 0; - } - if (ctx->indices.ptr) { - _sspine_free(ctx->indices.ptr); - ctx->indices.ptr = 0; - } - if (ctx->vertices.ptr) { - _sspine_free(ctx->vertices.ptr); - ctx->vertices.ptr = 0; - } -} - -static void _sspine_destroy_context(sspine_context ctx_id) { - _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - _sspine_deinit_context(ctx); - _sspine_context_pool_t* p = &_sspine.context_pool; - _sspine_clear(ctx, sizeof(_sspine_context_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(ctx_id.id)); - } -} - -static void _sspine_destroy_all_contexts(void) { - _sspine_context_pool_t* p = &_sspine.context_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_context_t* ctx = &p->items[i]; - _sspine_destroy_context(_sspine_make_context_handle(ctx->slot.id)); - } -} - -static sspine_context_desc _sspine_context_desc_defaults(const sspine_context_desc* desc) { - sspine_context_desc res = *desc; - res.max_vertices = _sspine_def(desc->max_vertices, _SSPINE_DEFAULT_MAX_VERTICES); - res.max_commands = _sspine_def(desc->max_commands, _SSPINE_DEFAULT_MAX_COMMANDS); - return res; -} - -static bool _sspine_is_default_context(sspine_context ctx_id) { - return ctx_id.id == 0x00010001; -} - -// █████ ████████ ██ █████ ███████ -// ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ███████ ███████ -// ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ██ ██ ███████ -// -// >>atlas -static void _sspine_setup_atlas_pool(int pool_size) { - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_atlas_t)); -} - -static void _sspine_discard_atlas_pool(void) { - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_atlas _sspine_make_atlas_handle(uint32_t id) { - sspine_atlas handle = { id }; - return handle; -} - -static _sspine_atlas_t* _sspine_atlas_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_atlas_t* _sspine_lookup_atlas(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_atlas_t* atlas = _sspine_atlas_at(id); - if (atlas->slot.id == id) { - return atlas; - } - } - return 0; -} - -static sspine_atlas _sspine_alloc_atlas(void) { - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _sspine_make_atlas_handle(id); - } else { - // pool exhausted - return _sspine_make_atlas_handle(SSPINE_INVALID_ID); - } -} - -static const _sspine_image_sampler_pair_t* _sspine_new_image_sampler_pair(sg_image img, sg_sampler smp) { - _sspine_image_sampler_pair_t* isp = (_sspine_image_sampler_pair_t*) _sspine_malloc_clear(sizeof(_sspine_image_sampler_pair_t)); - SOKOL_ASSERT(isp); - isp->img = img; - isp->smp = smp; - return isp; -} - -static void _sspine_delete_image_sampler_pair(const _sspine_image_sampler_pair_t* isp) { - if (isp) { - sg_destroy_sampler(isp->smp); - sg_destroy_image(isp->img); - _sspine_free((void*)isp); - } -} - -static sg_image _sspine_image_from_renderer_object(void* renderer_object) { - SOKOL_ASSERT(renderer_object); - const _sspine_image_sampler_pair_t* isp = (const _sspine_image_sampler_pair_t*)renderer_object; - return isp->img; -} - -static sg_sampler _sspine_sampler_from_renderer_object(void* renderer_object) { - SOKOL_ASSERT(renderer_object); - const _sspine_image_sampler_pair_t* isp = (const _sspine_image_sampler_pair_t*)renderer_object; - return isp->smp; -} - -static sspine_resource_state _sspine_init_atlas(_sspine_atlas_t* atlas, const sspine_atlas_desc* desc) { - SOKOL_ASSERT(atlas && (atlas->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - SOKOL_ASSERT(atlas->sp_atlas == 0); - - if ((0 == desc->data.ptr) || (0 == desc->data.size)) { - _SSPINE_ERROR(ATLAS_DESC_NO_DATA); - return SSPINE_RESOURCESTATE_FAILED; - } - atlas->overrides = desc->override; - - // NOTE: Spine doesn't detect when invalid or corrupt data is passed here, - // not much we can do about this... - atlas->sp_atlas = spAtlas_create((const char*)desc->data.ptr, (int)desc->data.size, "", 0); - if (0 == atlas->sp_atlas) { - _SSPINE_ERROR(SPINE_ATLAS_CREATION_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - - // allocate a sokol-gfx image and sampler object for each page, but the actual - // initialization needs to be delegated to the application - for (spAtlasPage* page = atlas->sp_atlas->pages; page != 0; page = page->next) { - atlas->num_pages++; - const sg_image img = sg_alloc_image(); - if (sg_query_image_state(img) != SG_RESOURCESTATE_ALLOC) { - _SSPINE_ERROR(SG_ALLOC_IMAGE_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - const sg_sampler smp = sg_alloc_sampler(); - if (sg_query_sampler_state(smp) != SG_RESOURCESTATE_ALLOC) { - _SSPINE_ERROR(SG_ALLOC_SAMPLER_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - - // need to put the image and sampler handle into a heap-alloc unfortunately, - // because a void* isn't big enough to stash two 32-bit handles into - // it directly on platforms with 32-bit pointers (like wasm) - page->rendererObject = (void*) _sspine_new_image_sampler_pair(img, smp); - - if (desc->override.premul_alpha_enabled) { - // NOTE: -1 is spine-c convention for 'true' - page->pma = -1; - } else if (desc->override.premul_alpha_disabled) { - page->pma = 0; - } - } - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_atlas(_sspine_atlas_t* atlas) { - if (atlas->sp_atlas) { - spAtlas_dispose(atlas->sp_atlas); - atlas->sp_atlas = 0; - } -} - -static void _sspine_destroy_atlas(sspine_atlas atlas_id) { - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - _sspine_deinit_atlas(atlas); - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - _sspine_clear(atlas, sizeof(_sspine_atlas_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(atlas_id.id)); - } -} - -static void _sspine_destroy_all_atlases(void) { - _sspine_atlas_pool_t* p = &_sspine.atlas_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_atlas_t* atlas = &p->items[i]; - _sspine_destroy_atlas(_sspine_make_atlas_handle(atlas->slot.id)); - } -} - -static sspine_atlas_desc _sspine_atlas_desc_defaults(const sspine_atlas_desc* desc) { - sspine_atlas_desc res = *desc; - return res; -} - -static spAtlasPage* _sspine_lookup_atlas_page(uint32_t atlas_id, int page_index) { - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id); - if (atlas) { - if ((page_index >= 0) && (page_index < atlas->num_pages)) { - int i = 0; - for (spAtlasPage* page = atlas->sp_atlas->pages; page != 0; page = page->next, i++) { - if (i == page_index) { - return page; - } - } - } - } - return 0; -} - -// ███████ ██ ██ ███████ ██ ███████ ████████ ██████ ███ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ -// ███████ █████ █████ ██ █████ ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ███████ ███████ ███████ ██ ██████ ██ ████ -// -// >>skeleton -static void _sspine_setup_skeleton_pool(int pool_size) { - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_skeleton_t)); -} - -static void _sspine_discard_skeleton_pool(void) { - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_skeleton _sspine_make_skeleton_handle(uint32_t id) { - sspine_skeleton handle = { id }; - return handle; -} - -static _sspine_skeleton_t* _sspine_skeleton_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_skeleton_t* _sspine_lookup_skeleton(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_skeleton_t* skeleton = _sspine_skeleton_at(id); - if (skeleton->slot.id == id) { - return skeleton; - } - } - return 0; -} - -static sspine_skeleton _sspine_alloc_skeleton(void) { - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _sspine_make_skeleton_handle(id); - } else { - // pool exhausted - return _sspine_make_skeleton_handle(SSPINE_INVALID_ID); - } -} - -static sspine_resource_state _sspine_init_skeleton(_sspine_skeleton_t* skeleton, const sspine_skeleton_desc* desc) { - SOKOL_ASSERT(skeleton && (skeleton->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - - if ((0 == desc->json_data) && ((0 == desc->binary_data.ptr) || (0 == desc->binary_data.size))) { - _SSPINE_ERROR(SKELETON_DESC_NO_DATA); - return SSPINE_RESOURCESTATE_FAILED; - } - if (desc->atlas.id == SSPINE_INVALID_ID) { - _SSPINE_ERROR(SKELETON_DESC_NO_ATLAS); - return SSPINE_RESOURCESTATE_FAILED; - } - - skeleton->atlas.id = desc->atlas.id; - skeleton->atlas.ptr = _sspine_lookup_atlas(skeleton->atlas.id); - if (!_sspine_atlas_ref_valid(&skeleton->atlas)) { - _SSPINE_ERROR(SKELETON_ATLAS_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - _sspine_atlas_t* atlas = skeleton->atlas.ptr; - if (SSPINE_RESOURCESTATE_VALID != atlas->slot.state) { - _SSPINE_ERROR(SKELETON_ATLAS_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT(atlas->sp_atlas); - - if (desc->json_data) { - spSkeletonJson* skel_json = spSkeletonJson_create(atlas->sp_atlas); - SOKOL_ASSERT(skel_json); - skel_json->scale = desc->prescale; - skeleton->sp_skel_data = spSkeletonJson_readSkeletonData(skel_json, desc->json_data); - spSkeletonJson_dispose(skel_json); skel_json = 0; - if (0 == skeleton->sp_skel_data) { - _SSPINE_ERROR(CREATE_SKELETON_DATA_FROM_JSON_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - } else { - spSkeletonBinary* skel_bin = spSkeletonBinary_create(atlas->sp_atlas); - SOKOL_ASSERT(skel_bin); - skel_bin->scale = desc->prescale; - skeleton->sp_skel_data = spSkeletonBinary_readSkeletonData(skel_bin, (const unsigned char*)desc->binary_data.ptr, (int)desc->binary_data.size); - spSkeletonBinary_dispose(skel_bin); skel_bin = 0; - if (0 == skeleton->sp_skel_data) { - _SSPINE_ERROR(CREATE_SKELETON_DATA_FROM_BINARY_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - } - SOKOL_ASSERT(skeleton->sp_skel_data); - - skeleton->sp_anim_data = spAnimationStateData_create(skeleton->sp_skel_data); - SOKOL_ASSERT(skeleton->sp_anim_data); - skeleton->sp_anim_data->defaultMix = desc->anim_default_mix; - - // get the max number of vertices in any mesh attachment - int max_vertex_count = 4; // number of vertices in a 'region attachment' (a 2-triangle quad) - const spSkeletonData* sp_skel_data = skeleton->sp_skel_data; - for (int skinIndex = 0; skinIndex < sp_skel_data->skinsCount; skinIndex++) { - const spSkin* sp_skin = sp_skel_data->skins[skinIndex]; - const spSkinEntry* skin_entry = spSkin_getAttachments(sp_skin); - if (skin_entry) do { - if (skin_entry->attachment) { - if (skin_entry->attachment->type == SP_ATTACHMENT_MESH) { - const spMeshAttachment* mesh_attachment = (spMeshAttachment*)skin_entry->attachment; - // worldVerticesLength is number of floats - SOKOL_ASSERT((mesh_attachment->super.worldVerticesLength & 1) == 0); - const int num_vertices = mesh_attachment->super.worldVerticesLength / 2; - if (num_vertices > max_vertex_count) { - max_vertex_count = num_vertices; - } - } - } - } while ((skin_entry = skin_entry->next) != 0); - } - - // allocate a shared vertex transform buffer (big enough to hold vertices for biggest mesh attachment) - skeleton->tform_buf.cap = max_vertex_count; - skeleton->tform_buf.ptr = (sspine_vec2*) _sspine_malloc((size_t)skeleton->tform_buf.cap * sizeof(sspine_vec2)); - - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_skeleton(_sspine_skeleton_t* skeleton) { - if (skeleton->tform_buf.ptr) { - _sspine_free(skeleton->tform_buf.ptr); - skeleton->tform_buf.ptr = 0; - } - if (skeleton->sp_anim_data) { - spAnimationStateData_dispose(skeleton->sp_anim_data); - skeleton->sp_anim_data = 0; - } - if (skeleton->sp_skel_data) { - spSkeletonData_dispose(skeleton->sp_skel_data); - skeleton->sp_skel_data = 0; - } -} - -static void _sspine_destroy_skeleton(sspine_skeleton skeleton_id) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (skeleton) { - _sspine_deinit_skeleton(skeleton); - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - _sspine_clear(skeleton, sizeof(_sspine_skeleton_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(skeleton_id.id)); - } -} - -static void _sspine_destroy_all_skeletons(void) { - _sspine_skeleton_pool_t* p = &_sspine.skeleton_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_skeleton_t* skeleton = &p->items[i]; - _sspine_destroy_skeleton(_sspine_make_skeleton_handle(skeleton->slot.id)); - } -} - -static sspine_skeleton_desc _sspine_skeleton_desc_defaults(const sspine_skeleton_desc* desc) { - sspine_skeleton_desc res = *desc; - res.prescale = _sspine_def(desc->prescale, 1.0f); - res.anim_default_mix = _sspine_def(desc->anim_default_mix, 0.2f); - return res; -} - -static spBoneData* _sspine_lookup_bone_data(uint32_t skeleton_id, int bone_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->bones); - if ((bone_index >= 0) && (bone_index <= skeleton->sp_skel_data->bonesCount)) { - return skeleton->sp_skel_data->bones[bone_index]; - } - } - return 0; -} - -static spSlotData* _sspine_lookup_slot_data(uint32_t skeleton_id, int slot_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->slots); - if ((slot_index >= 0) && (slot_index <= skeleton->sp_skel_data->slotsCount)) { - return skeleton->sp_skel_data->slots[slot_index]; - } - } - return 0; -} - -static spEventData* _sspine_lookup_event_data(uint32_t skeleton_id, int event_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->events); - if ((event_index >= 0) && (event_index < skeleton->sp_skel_data->eventsCount)) { - return skeleton->sp_skel_data->events[event_index]; - } - } - return 0; -} - -static spIkConstraintData* _sspine_lookup_ikconstraint_data(uint32_t skeleton_id, int iktarget_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->ikConstraints); - if ((iktarget_index >= 0) && (iktarget_index < skeleton->sp_skel_data->ikConstraintsCount)) { - return skeleton->sp_skel_data->ikConstraints[iktarget_index]; - } - } - return 0; -} - -static spSkin* _sspine_lookup_skin(uint32_t skeleton_id, int skin_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data && skeleton->sp_skel_data->skins); - if ((skin_index >= 0) && (skin_index < skeleton->sp_skel_data->skinsCount)) { - return skeleton->sp_skel_data->skins[skin_index]; - } - } - return 0; -} - -// ███████ ██ ██ ██ ███ ██ ███████ ███████ ████████ -// ██ ██ ██ ██ ████ ██ ██ ██ ██ -// ███████ █████ ██ ██ ██ ██ ███████ █████ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ███████ ██ ██ ██ ██ ████ ███████ ███████ ██ -// -// >>skinset -static void _sspine_setup_skinset_pool(int pool_size) { - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_skinset_t)); -} - -static void _sspine_discard_skinset_pool(void) { - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_skinset _sspine_make_skinset_handle(uint32_t id) { - sspine_skinset handle = { id }; - return handle; -} - -static _sspine_skinset_t* _sspine_skinset_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_skinset_t* _sspine_lookup_skinset(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_skinset_t* skinset = _sspine_skinset_at(id); - if (skinset->slot.id == id) { - return skinset; - } - } - return 0; -} - -static sspine_skinset _sspine_alloc_skinset(void) { - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - return _sspine_make_skinset_handle(id); - } else { - // pool exhausted - return _sspine_make_skinset_handle(SSPINE_INVALID_ID); - } -} - -static sspine_resource_state _sspine_init_skinset(_sspine_skinset_t* skinset, const sspine_skinset_desc* desc) { - SOKOL_ASSERT(skinset && (skinset->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - - if (desc->skeleton.id == SSPINE_INVALID_ID) { - _SSPINE_ERROR(SKINSET_DESC_NO_SKELETON); - return SSPINE_RESOURCESTATE_FAILED; - } - skinset->skel.id = desc->skeleton.id; - skinset->skel.ptr = _sspine_lookup_skeleton(desc->skeleton.id); - if (!_sspine_skeleton_ref_valid(&skinset->skel)) { - _SSPINE_ERROR(SKINSET_SKELETON_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - _sspine_skeleton_t* skel = skinset->skel.ptr; - if (SSPINE_RESOURCESTATE_VALID != skel->slot.state) { - _SSPINE_ERROR(SKINSET_SKELETON_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT(skel->sp_skel_data); - skinset->sp_skin = spSkin_create("skinset"); - for (int i = 0; i < SSPINE_MAX_SKINSET_SKINS; i++) { - if (desc->skins[i].skeleton_id != SSPINE_INVALID_ID) { - spSkin* skin = _sspine_lookup_skin(desc->skins[i].skeleton_id, desc->skins[i].index); - if (0 == skin) { - _SSPINE_ERROR(SKINSET_INVALID_SKIN_HANDLE); - return SSPINE_RESOURCESTATE_FAILED; - } - spSkin_addSkin(skinset->sp_skin, skin); - } - } - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_skinset(_sspine_skinset_t* skinset) { - if (skinset->sp_skin) { - spSkin_clear(skinset->sp_skin); - spSkin_dispose(skinset->sp_skin); - skinset->sp_skin = 0; - } -} - -static void _sspine_destroy_skinset(sspine_skinset skinset_id) { - _sspine_skinset_t* skinset = _sspine_lookup_skinset(skinset_id.id); - if (skinset) { - _sspine_deinit_skinset(skinset); - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - _sspine_clear(skinset, sizeof(_sspine_skinset_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(skinset_id.id)); - } -} - -static void _sspine_destroy_all_skinsets(void) { - _sspine_skinset_pool_t* p = &_sspine.skinset_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_skinset_t* skinset = &p->items[i]; - _sspine_destroy_skinset(_sspine_make_skinset_handle(skinset->slot.id)); - } -} - -static sspine_skinset_desc _sspine_skinset_desc_defaults(const sspine_skinset_desc* desc) { - sspine_skinset_desc res = *desc; - return res; -} - -// ██ ███ ██ ███████ ████████ █████ ███ ██ ██████ ███████ -// ██ ████ ██ ██ ██ ██ ██ ████ ██ ██ ██ -// ██ ██ ██ ██ ███████ ██ ███████ ██ ██ ██ ██ █████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ████ ███████ ██ ██ ██ ██ ████ ██████ ███████ -// -// >>instance -static void _sspine_setup_instance_pool(int pool_size) { - _sspine_instance_pool_t* p = &_sspine.instance_pool; - _sspine_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_sspine_instance_t)); -} - -static void _sspine_discard_instance_pool(void) { - _sspine_instance_pool_t* p = &_sspine.instance_pool; - _sspine_discard_item_pool(&p->pool, (void**)&p->items); -} - -static sspine_instance _sspine_make_instance_handle(uint32_t id) { - sspine_instance handle = { id }; - return handle; -} - -static _sspine_instance_t* _sspine_instance_at(uint32_t id) { - SOKOL_ASSERT(SSPINE_INVALID_ID != id); - const _sspine_instance_pool_t* p = &_sspine.instance_pool; - int slot_index = _sspine_slot_index(id); - SOKOL_ASSERT((slot_index > _SSPINE_INVALID_SLOT_INDEX) && (slot_index < p->pool.size)); - return &p->items[slot_index]; -} - -static _sspine_instance_t* _sspine_lookup_instance(uint32_t id) { - if (SSPINE_INVALID_ID != id) { - _sspine_instance_t* instance = _sspine_instance_at(id); - if (instance->slot.id == id) { - return instance; - } - } - return 0; -} - -static sspine_instance _sspine_alloc_instance(void) { - _sspine_instance_pool_t* p = &_sspine.instance_pool; - sspine_instance res; - int slot_index = _sspine_pool_alloc_index(&p->pool); - if (_SSPINE_INVALID_SLOT_INDEX != slot_index) { - uint32_t id = _sspine_slot_init(&p->pool, &p->items[slot_index].slot, slot_index); - res = _sspine_make_instance_handle(id); - } else { - // pool exhausted - res = _sspine_make_instance_handle(SSPINE_INVALID_ID); - } - return res; -} - -static void _sspine_rewind_triggered_events(_sspine_instance_t* instance) { - instance->cur_triggered_event_index = 0; - _sspine_clear(instance->triggered_events, sizeof(instance->triggered_events)); -} - -static sspine_triggered_event_info* _sspine_next_triggered_event_info(_sspine_instance_t* instance) { - if (instance->cur_triggered_event_index < _SSPINE_MAX_TRIGGERED_EVENTS) { - return &instance->triggered_events[instance->cur_triggered_event_index++]; - } else { - return 0; - } -} - -static void _sspine_event_listener(spAnimationState* sp_anim_state, spEventType sp_event_type, spTrackEntry* sp_track_entry, spEvent* sp_event) { - if (sp_event_type == SP_ANIMATION_EVENT) { - SOKOL_ASSERT(sp_anim_state && sp_track_entry && sp_event); (void)sp_track_entry; - SOKOL_ASSERT(sp_event->data && sp_event->data->name); - _sspine_instance_t* instance = _sspine_lookup_instance((uint32_t)(uintptr_t)sp_anim_state->userData); - if (_sspine_instance_and_deps_valid(instance)) { - sspine_triggered_event_info* info = _sspine_next_triggered_event_info(instance); - if (info) { - // FIXME: this sucks, but we really need the event index - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(instance->skel.id); - SOKOL_ASSERT(skeleton && skeleton->sp_skel_data->events); - const spEventData* sp_event_data = sp_event->data; - for (int i = 0; i < skeleton->sp_skel_data->eventsCount; i++) { - if (sp_event_data == skeleton->sp_skel_data->events[i]) { - info->event = _sspine_event(skeleton->slot.id, i); - break; - } - } - SOKOL_ASSERT(info->event.skeleton_id != SSPINE_INVALID_ID); - info->valid = true; - info->time = sp_event->time; - info->int_value = sp_event->intValue; - info->float_value = sp_event->floatValue; - info->volume = sp_event->volume; - info->balance = sp_event->balance; - info->string_value = _sspine_string(sp_event->stringValue); - if (info->string_value.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - } - } -} - -static sspine_resource_state _sspine_init_instance(_sspine_instance_t* instance, const sspine_instance_desc* desc) { - SOKOL_ASSERT(instance && (instance->slot.state == SSPINE_RESOURCESTATE_ALLOC)); - SOKOL_ASSERT(desc); - - if (desc->skeleton.id == SSPINE_INVALID_ID) { - _SSPINE_ERROR(INSTANCE_DESC_NO_SKELETON); - return SSPINE_RESOURCESTATE_FAILED; - } - instance->skel.id = desc->skeleton.id; - instance->skel.ptr = _sspine_lookup_skeleton(instance->skel.id); - if (!_sspine_skeleton_ref_valid(&instance->skel)) { - _SSPINE_ERROR(INSTANCE_SKELETON_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - _sspine_skeleton_t* skel = instance->skel.ptr; - if (SSPINE_RESOURCESTATE_VALID != skel->slot.state) { - _SSPINE_ERROR(INSTANCE_SKELETON_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - instance->atlas = skel->atlas; - if (!_sspine_atlas_ref_valid(&instance->atlas)) { - _SSPINE_ERROR(INSTANCE_ATLAS_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - if (SSPINE_RESOURCESTATE_VALID != instance->atlas.ptr->slot.state) { - _SSPINE_ERROR(INSTANCE_ATLAS_NOT_VALID); - return SSPINE_RESOURCESTATE_FAILED; - } - SOKOL_ASSERT(skel->sp_skel_data); - SOKOL_ASSERT(skel->sp_anim_data); - - instance->sp_skel = spSkeleton_create(skel->sp_skel_data); - if (0 == instance->sp_skel) { - _SSPINE_ERROR(SPINE_SKELETON_CREATION_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - instance->sp_anim_state = spAnimationState_create(skel->sp_anim_data); - if (0 == instance->sp_anim_state) { - _SSPINE_ERROR(SPINE_ANIMATIONSTATE_CREATION_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - instance->sp_clip = spSkeletonClipping_create(); - if (0 == instance->sp_clip) { - _SSPINE_ERROR(SPINE_SKELETONCLIPPING_CREATION_FAILED); - return SSPINE_RESOURCESTATE_FAILED; - } - - instance->sp_anim_state->userData = (void*)(uintptr_t)instance->slot.id; - instance->sp_anim_state->listener = _sspine_event_listener; - - spSkeleton_setToSetupPose(instance->sp_skel); - spAnimationState_update(instance->sp_anim_state, 0.0f); - spAnimationState_apply(instance->sp_anim_state, instance->sp_skel); - spSkeleton_updateWorldTransform(instance->sp_skel); - - return SSPINE_RESOURCESTATE_VALID; -} - -static void _sspine_deinit_instance(_sspine_instance_t* instance) { - if (instance->sp_clip) { - spSkeletonClipping_dispose(instance->sp_clip); - instance->sp_clip = 0; - } - if (instance->sp_anim_state) { - spAnimationState_dispose(instance->sp_anim_state); - instance->sp_anim_state = 0; - } - if (instance->sp_skel) { - spSkeleton_dispose(instance->sp_skel); - instance->sp_skel = 0; - } -} - -static void _sspine_destroy_instance(sspine_instance instance_id) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - _sspine_deinit_instance(instance); - _sspine_instance_pool_t* p = &_sspine.instance_pool; - _sspine_clear(instance, sizeof(_sspine_instance_t)); - _sspine_pool_free_index(&p->pool, _sspine_slot_index(instance_id.id)); - } -} - -static void _sspine_destroy_all_instances(void) { - _sspine_instance_pool_t* p = &_sspine.instance_pool; - for (int i = 0; i < p->pool.size; i++) { - _sspine_instance_t* instance = &p->items[i]; - _sspine_destroy_instance(_sspine_make_instance_handle(instance->slot.id)); - } -} - -static spAnimation* _sspine_lookup_skeleton_anim(uint32_t skeleton_id, int anim_index) { - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - if ((anim_index >= 0) && (anim_index < skeleton->sp_skel_data->animationsCount)) { - return skeleton->sp_skel_data->animations[anim_index]; - } - } - return 0; -} - -static spAnimation* _sspine_lookup_instance_anim(uint32_t instance_id, uint32_t skeleton_id, int anim_index) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel && instance->sp_skel->data); - if ((anim_index >= 0) && (anim_index < instance->sp_skel->data->animationsCount)) { - return instance->sp_skel->data->animations[anim_index]; - } - } - return 0; -} - -static spBone* _sspine_lookup_bone(uint32_t instance_id, uint32_t skeleton_id, int bone_index) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel && instance->sp_skel->bones); - if ((bone_index >= 0) && (bone_index <= instance->sp_skel->bonesCount)) { - return instance->sp_skel->bones[bone_index]; - } - } - return 0; -} - -static spSlot* _sspine_lookup_slot(uint32_t instance_id, uint32_t skeleton_id, int slot_index) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel && instance->sp_skel->slots); - if ((slot_index >= 0) && (slot_index <= instance->sp_skel->slotsCount)) { - return instance->sp_skel->slots[slot_index]; - } - } - return 0; -} - -static spIkConstraint* _sspine_lookup_ikconstraint(uint32_t instance_id, uint32_t skeleton_id, int iktarget_index) { - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel && instance->sp_skel->ikConstraints); - if ((iktarget_index >= 0) && (iktarget_index < instance->sp_skel->ikConstraintsCount)) { - return instance->sp_skel->ikConstraints[iktarget_index]; - } - } - return 0; -} - -static sspine_instance_desc _sspine_instance_desc_defaults(const sspine_instance_desc* desc) { - sspine_instance_desc res = *desc; - return res; -} - -// ██████ ██████ █████ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██ ██████ ███████ ██ █ ██ -// ██ ██ ██ ██ ██ ██ ██ ███ ██ -// ██████ ██ ██ ██ ██ ███ ███ -// -// >>draw -static void _sspine_check_rewind_commands(_sspine_context_t* ctx) { - if (_sspine.frame_id != ctx->commands.rewind_frame_id) { - ctx->commands.next = 0; - ctx->commands.rewind_frame_id = _sspine.frame_id; - } -} - -static _sspine_command_t* _sspine_next_command(_sspine_context_t* ctx) { - _sspine_check_rewind_commands(ctx); - if (ctx->commands.next < ctx->commands.cap) { - return &(ctx->commands.ptr[ctx->commands.next++]); - } else { - _SSPINE_ERROR(COMMAND_BUFFER_FULL); - return 0; - } -} - -static _sspine_command_t* _sspine_cur_command(_sspine_context_t* ctx) { - _sspine_check_rewind_commands(ctx); - if (ctx->commands.next > 0) { - return &ctx->commands.ptr[ctx->commands.next - 1]; - } else { - return 0; - } -} - -static void _sspine_check_rewind_vertices(_sspine_context_t* ctx) { - if (_sspine.frame_id != ctx->vertices.rewind_frame_id) { - ctx->vertices.next = 0; - ctx->vertices.rewind_frame_id = _sspine.frame_id; - } -} - -static _sspine_alloc_vertices_result_t _sspine_alloc_vertices(_sspine_context_t* ctx, int num) { - _sspine_check_rewind_vertices(ctx); - _sspine_alloc_vertices_result_t res; - _sspine_clear(&res, sizeof(res)); - if ((ctx->vertices.next + num) <= ctx->vertices.cap) { - res.ptr = &(ctx->vertices.ptr[ctx->vertices.next]); - res.index = ctx->vertices.next; - ctx->vertices.next += num; - } else { - _SSPINE_ERROR(VERTEX_BUFFER_FULL); - } - return res; -} - -static void _sspine_check_rewind_indices(_sspine_context_t* ctx) { - if (_sspine.frame_id != ctx->indices.rewind_frame_id) { - ctx->indices.next = 0; - ctx->indices.rewind_frame_id = _sspine.frame_id; - } -} - -static _sspine_alloc_indices_result_t _sspine_alloc_indices(_sspine_context_t* ctx, int num) { - _sspine_check_rewind_indices(ctx); - _sspine_alloc_indices_result_t res; - _sspine_clear(&res, sizeof(res)); - if ((ctx->indices.next + num) <= ctx->indices.cap) { - res.ptr = &(ctx->indices.ptr[ctx->indices.next]); - res.index = ctx->indices.next; - ctx->indices.next += num; - } else { - _SSPINE_ERROR(INDEX_BUFFER_FULL); - } - return res; -} - -static void _sspine_draw_instance(_sspine_context_t* ctx, _sspine_instance_t* instance, int layer) { - SOKOL_ASSERT(_sspine_instance_and_deps_valid(instance)); - SOKOL_ASSERT(instance->sp_skel); - SOKOL_ASSERT(instance->sp_anim_state); - SOKOL_ASSERT(instance->sp_clip); - - // see: https://github.com/EsotericSoftware/spine-runtimes/blob/4.1/spine-sdl/src/spine-sdl-c.c - const spSkeleton* sp_skel = instance->sp_skel; - float* tform_buf = (float*)instance->skel.ptr->tform_buf.ptr; - const int max_tform_buf_verts = instance->skel.ptr->tform_buf.cap; - SOKOL_UNUSED(max_tform_buf_verts); // only used in asserts - const int tform_buf_stride = 2; // each element is 2 floats - spSkeletonClipping* sp_clip = instance->sp_clip; - for (int slot_index = 0; slot_index < sp_skel->slotsCount; slot_index++) { - spSlot* sp_slot = sp_skel->drawOrder[slot_index]; - if (!sp_slot->attachment) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - - // early out if the slot alpha is 0 or the bone is not active - // FIXME: does alpha 0 actually mean 'invisible' for all blend modes? - if ((sp_slot->color.a == 0) || (!sp_slot->bone->active)) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - - int num_vertices = 0; - float* uvs = 0; - float* vertices = 0; - int num_indices = 0; - const uint16_t* indices = 0; - const spColor* att_color = 0; - sg_image img = { SG_INVALID_ID }; - sg_sampler smp = { SG_INVALID_ID }; - bool premul_alpha = false; - if (sp_slot->attachment->type == SP_ATTACHMENT_REGION) { - static const uint16_t quad_indices[] = { 0, 1, 2, 2, 3, 0 }; - spRegionAttachment* region = (spRegionAttachment*)sp_slot->attachment; - att_color = ®ion->color; - // FIXME(?) early out if the slot alpha is 0 - if (att_color->a == 0) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - spRegionAttachment_computeWorldVertices(region, sp_slot, tform_buf, 0, tform_buf_stride); - vertices = tform_buf; - num_vertices = 4; - indices = &quad_indices[0]; - num_indices = 6; - uvs = region->uvs; - const spAtlasPage* sp_page = ((spAtlasRegion*)region->rendererObject)->page; - img = _sspine_image_from_renderer_object(sp_page->rendererObject); - smp = _sspine_sampler_from_renderer_object(sp_page->rendererObject); - premul_alpha = sp_page->pma != 0; - } else if (sp_slot->attachment->type == SP_ATTACHMENT_MESH) { - spMeshAttachment* mesh = (spMeshAttachment*)sp_slot->attachment; - att_color = &mesh->color; - // FIXME(?) early out if the slot alpha is 0 - if (att_color->a == 0) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - const int num_floats = mesh->super.worldVerticesLength; - num_vertices = num_floats / 2; - SOKOL_ASSERT(num_vertices <= max_tform_buf_verts); - spVertexAttachment_computeWorldVertices(&mesh->super, sp_slot, 0, num_floats, tform_buf, 0, tform_buf_stride); - vertices = tform_buf; - indices = mesh->triangles; - num_indices = mesh->trianglesCount; // actually indicesCount??? - uvs = mesh->uvs; - const spAtlasPage* sp_page = ((spAtlasRegion*)mesh->rendererObject)->page; - img = _sspine_image_from_renderer_object(sp_page->rendererObject); - smp = _sspine_sampler_from_renderer_object(sp_page->rendererObject); - premul_alpha = sp_page->pma != 0; - } else if (sp_slot->attachment->type == SP_ATTACHMENT_CLIPPING) { - spClippingAttachment* clip_attachment = (spClippingAttachment*) sp_slot->attachment; - spSkeletonClipping_clipStart(sp_clip, sp_slot, clip_attachment); - continue; - } else { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - SOKOL_ASSERT(vertices && (num_vertices > 0)); - SOKOL_ASSERT(indices && (num_indices > 0)); - SOKOL_ASSERT(uvs); - SOKOL_ASSERT(img.id != SG_INVALID_ID); - SOKOL_ASSERT(smp.id != SG_INVALID_ID); - - if (spSkeletonClipping_isClipping(sp_clip)) { - spSkeletonClipping_clipTriangles(sp_clip, tform_buf, num_vertices * 2, (uint16_t*)indices, num_indices, uvs, tform_buf_stride); - vertices = sp_clip->clippedVertices->items; - num_vertices = sp_clip->clippedVertices->size / 2; - uvs = sp_clip->clippedUVs->items; - indices = sp_clip->clippedTriangles->items; - num_indices = sp_clip->clippedTriangles->size; - } - SOKOL_ASSERT(vertices); - SOKOL_ASSERT(indices); - SOKOL_ASSERT(uvs); - - // there might be no geometry to render after clipping - if ((0 == num_vertices) || (0 == num_indices)) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - - const _sspine_alloc_vertices_result_t dst_vertices = _sspine_alloc_vertices(ctx, num_vertices); - const _sspine_alloc_indices_result_t dst_indices = _sspine_alloc_indices(ctx, num_indices); - if ((0 == dst_vertices.ptr) || (0 == dst_indices.ptr)) { - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - continue; - } - - // write transformed and potentially clipped vertices and indices - const uint8_t r = (uint8_t)(sp_skel->color.r * sp_slot->color.r * att_color->r * 255.0f); - const uint8_t g = (uint8_t)(sp_skel->color.g * sp_slot->color.g * att_color->g * 255.0f); - const uint8_t b = (uint8_t)(sp_skel->color.b * sp_slot->color.b * att_color->b * 255.0f); - const uint8_t a = (uint8_t)(sp_skel->color.a * sp_slot->color.a * att_color->a * 255.0f); - const uint32_t color = (((uint32_t)a<<24) | ((uint32_t)b<<16) | ((uint32_t)g<<8) | (uint32_t)r); - for (int vi = 0; vi < num_vertices; vi++) { - dst_vertices.ptr[vi].pos.x = vertices[vi*2]; - dst_vertices.ptr[vi].pos.y = vertices[vi*2 + 1]; - dst_vertices.ptr[vi].color = color; - dst_vertices.ptr[vi].uv.x = uvs[vi*2]; - dst_vertices.ptr[vi].uv.y = uvs[vi*2 + 1]; - } - for (int ii = 0; ii < num_indices; ii++) { - dst_indices.ptr[ii] = (uint32_t)indices[ii] + (uint32_t)dst_vertices.index; - } - - sg_pipeline pip = { SG_INVALID_ID }; - // NOTE: pma == 0.0: use color from texture as is - // pma == 1.0: multiply texture rgb by texture alpha in fragment shader - float pma = 0.0f; - switch (sp_slot->data->blendMode) { - case SP_BLEND_MODE_NORMAL: - case SP_BLEND_MODE_ADDITIVE: - case SP_BLEND_MODE_SCREEN: - pip = ctx->pip.normal_additive; - pma = premul_alpha ? 0.0f : 1.0f; // NOT A BUG - break; - case SP_BLEND_MODE_MULTIPLY: - pip = ctx->pip.multiply; - pma = 0.0f; // always use texture color as is - break; - } - - // write new draw command, or merge with current draw command - _sspine_command_t* cur_cmd = _sspine_cur_command(ctx); - if (cur_cmd - && (cur_cmd->layer == layer) - && (cur_cmd->pip.id == pip.id) - && (cur_cmd->img.id == img.id) - && (cur_cmd->smp.id == smp.id) - && (cur_cmd->pma == pma)) - { - // merge with current command - cur_cmd->num_elements += num_indices; - } else { - // record a new command - _sspine_command_t* cmd_ptr = _sspine_next_command(ctx); - if (cmd_ptr) { - cmd_ptr->layer = layer; - cmd_ptr->pip = pip; - cmd_ptr->img = img; - cmd_ptr->smp = smp; - cmd_ptr->pma = pma; - cmd_ptr->base_element = dst_indices.index; - cmd_ptr->num_elements = num_indices; - } - } - spSkeletonClipping_clipEnd(sp_clip, sp_slot); - } - spSkeletonClipping_clipEnd2(sp_clip); -} - -// compute orthographic projection matrix -static void _sspine_layer_transform_to_proj(const sspine_layer_transform* tform, float* res) { - const float left = -tform->origin.x; - const float right = tform->size.x - tform->origin.x; - const float top = -tform->origin.y; - const float bottom = tform->size.y - tform->origin.y; - const float znear = -1.0f; - const float zfar = 1.0f; - res[0] = 2.0f / (right - left); - res[1] = 0.0f; - res[2] = 0.0f; - res[3] = 0.0f; - res[4] = 0.0f; - res[5] = 2.0f / (top - bottom); - res[6] = 0.0f; - res[7] = 0.0f; - res[8] = 0.0f; - res[9] = 0.0f; - res[10] = -2.0f / (zfar - znear); - res[11] = 0.0f; - res[12] = -(right + left) / (right - left); - res[13] = -(top + bottom) / (top - bottom); - res[14] = -(zfar + znear) / (zfar - znear); - res[15] = 1.0f; -} - -static _sspine_vsparams_t _sspine_compute_vsparams(const sspine_layer_transform* tform) { - _sspine_vsparams_t p; - _sspine_clear(&p, sizeof(p)); - _sspine_layer_transform_to_proj(tform, p.mvp); - return p; -} - -static void _sspine_draw_layer(_sspine_context_t* ctx, int layer, const sspine_layer_transform* tform) { - if ((ctx->vertices.next > 0) && (ctx->commands.next > 0)) { - sg_push_debug_group("sokol-spine"); - - if (ctx->update_frame_id != _sspine.frame_id) { - ctx->update_frame_id = _sspine.frame_id; - const sg_range vtx_range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sspine_vertex_t) }; - sg_update_buffer(ctx->vbuf, &vtx_range); - const sg_range idx_range = { ctx->indices.ptr, (size_t)ctx->indices.next * sizeof(uint32_t) }; - sg_update_buffer(ctx->ibuf, &idx_range); - } - - _sspine_vsparams_t vsparams = _sspine_compute_vsparams(tform); - const sg_range vsparams_range = { &vsparams, sizeof(vsparams) }; - _sspine_fsparams_t fsparams; - _sspine_clear(&fsparams, sizeof(fsparams)); - const sg_range fsparams_range = { &fsparams, sizeof(fsparams) }; - - uint32_t cur_pip_id = SG_INVALID_ID; - uint32_t cur_img_id = SG_INVALID_ID; - uint32_t cur_smp_id = SG_INVALID_ID; - float cur_pma = -1.0f; - for (int i = 0; i < ctx->commands.next; i++) { - const _sspine_command_t* cmd = &ctx->commands.ptr[i]; - const bool img_valid = sg_query_image_state(cmd->img) == SG_RESOURCESTATE_VALID; - const bool smp_valid = sg_query_sampler_state(cmd->smp) == SG_RESOURCESTATE_VALID; - if ((layer == cmd->layer) && img_valid && smp_valid) { - if (cur_pip_id != cmd->pip.id) { - sg_apply_pipeline(cmd->pip); - cur_pip_id = cmd->pip.id; - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &vsparams_range); - cur_img_id = SG_INVALID_ID; - } - if ((cur_img_id != cmd->img.id) || (cur_smp_id != cmd->smp.id)) { - ctx->bind.fs.images[0] = cmd->img; - ctx->bind.fs.samplers[0] = cmd->smp; - sg_apply_bindings(&ctx->bind); - cur_img_id = cmd->img.id; - cur_smp_id = cmd->smp.id; - } - if (cur_pma != cmd->pma) { - fsparams.pma = cmd->pma; - sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, &fsparams_range); - cur_pma = cmd->pma; - } - if (cmd->num_elements > 0) { - sg_draw(cmd->base_element, cmd->num_elements, 1); - } - } - } - sg_pop_debug_group(); - } -} - -// ███ ███ ██ ███████ ██████ -// ████ ████ ██ ██ ██ -// ██ ████ ██ ██ ███████ ██ -// ██ ██ ██ ██ ██ ██ -// ██ ██ ██ ███████ ██████ -// -// >>misc - -// return sspine_desc with patched defaults -static sspine_desc _sspine_desc_defaults(const sspine_desc* desc) { - SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); - sspine_desc res = *desc; - res.max_vertices = _sspine_def(desc->max_vertices, _SSPINE_DEFAULT_MAX_VERTICES); - res.max_commands = _sspine_def(desc->max_commands, _SSPINE_DEFAULT_MAX_COMMANDS); - res.context_pool_size = _sspine_def(desc->context_pool_size, _SSPINE_DEFAULT_CONTEXT_POOL_SIZE); - res.atlas_pool_size = _sspine_def(desc->atlas_pool_size, _SSPINE_DEFAULT_ATLAS_POOL_SIZE); - res.skeleton_pool_size = _sspine_def(desc->skeleton_pool_size, _SSPINE_DEFAULT_SKELETON_POOL_SIZE); - res.skinset_pool_size = _sspine_def(desc->skinset_pool_size, _SSPINE_DEFAULT_SKINSET_POOL_SIZE); - res.instance_pool_size = _sspine_def(desc->instance_pool_size, _SSPINE_DEFAULT_INSTANCE_POOL_SIZE); - return res; -} - -static sspine_context_desc _sspine_as_context_desc(const sspine_desc* desc) { - sspine_context_desc ctx_desc; - _sspine_clear(&ctx_desc, sizeof(ctx_desc)); - ctx_desc.max_vertices = desc->max_vertices; - ctx_desc.max_commands = desc->max_commands; - ctx_desc.color_format = desc->color_format; - ctx_desc.depth_format = desc->depth_format; - ctx_desc.sample_count = desc->sample_count; - ctx_desc.color_write_mask = desc->color_write_mask; - return ctx_desc; -} - -static sg_filter _sspine_as_sampler_filter(spAtlasFilter filter) { - switch (filter) { - case SP_ATLAS_UNKNOWN_FILTER: return _SG_FILTER_DEFAULT; - case SP_ATLAS_NEAREST: return SG_FILTER_NEAREST; - case SP_ATLAS_LINEAR: return SG_FILTER_LINEAR; - case SP_ATLAS_MIPMAP: return SG_FILTER_LINEAR; - case SP_ATLAS_MIPMAP_NEAREST_NEAREST: return SG_FILTER_NEAREST; - case SP_ATLAS_MIPMAP_LINEAR_NEAREST: return SG_FILTER_LINEAR; - case SP_ATLAS_MIPMAP_NEAREST_LINEAR: return SG_FILTER_NEAREST; - case SP_ATLAS_MIPMAP_LINEAR_LINEAR: return SG_FILTER_LINEAR; - default: return SG_FILTER_LINEAR; - } -} - -static sg_filter _sspine_as_sampler_mipmap_filter(spAtlasFilter filter) { - switch (filter) { - case SP_ATLAS_UNKNOWN_FILTER: - return _SG_FILTER_DEFAULT; - case SP_ATLAS_NEAREST: - case SP_ATLAS_LINEAR: - case SP_ATLAS_MIPMAP: - case SP_ATLAS_MIPMAP_NEAREST_NEAREST: - case SP_ATLAS_MIPMAP_LINEAR_NEAREST: - return SG_FILTER_NEAREST; - case SP_ATLAS_MIPMAP_NEAREST_LINEAR: - case SP_ATLAS_MIPMAP_LINEAR_LINEAR: - return SG_FILTER_LINEAR; - default: - return SG_FILTER_NEAREST; - } -} - -static sg_wrap _sspine_as_sampler_wrap(spAtlasWrap wrap) { - switch (wrap) { - case SP_ATLAS_MIRROREDREPEAT: return SG_WRAP_MIRRORED_REPEAT; - case SP_ATLAS_CLAMPTOEDGE: return SG_WRAP_CLAMP_TO_EDGE; - case SP_ATLAS_REPEAT: return SG_WRAP_REPEAT; - default: return _SG_WRAP_DEFAULT; - } -} - -static void _sspine_init_image_info(const _sspine_atlas_t* atlas, int index, sspine_image_info* info, bool with_overrides) { - spAtlasPage* page = _sspine_lookup_atlas_page(atlas->slot.id, index); - SOKOL_ASSERT(page); - SOKOL_ASSERT(page->name); - info->valid = true; - info->sgimage = _sspine_image_from_renderer_object(page->rendererObject); - info->sgsampler = _sspine_sampler_from_renderer_object(page->rendererObject); - if (with_overrides && (atlas->overrides.min_filter != _SG_FILTER_DEFAULT)) { - info->min_filter = atlas->overrides.min_filter; - } else { - info->min_filter = _sspine_as_sampler_filter(page->minFilter); - } - if (with_overrides && (atlas->overrides.mag_filter != _SG_FILTER_DEFAULT)) { - info->mag_filter = atlas->overrides.mag_filter; - } else { - info->mag_filter = _sspine_as_sampler_filter(page->magFilter); - } - if (with_overrides && (atlas->overrides.mipmap_filter != _SG_FILTER_DEFAULT)) { - info->mipmap_filter = atlas->overrides.mipmap_filter; - } else { - info->mipmap_filter = _sspine_as_sampler_mipmap_filter(page->minFilter); - } - if (with_overrides && (atlas->overrides.wrap_u != _SG_WRAP_DEFAULT)) { - info->wrap_u = atlas->overrides.wrap_u; - } else { - info->wrap_u = _sspine_as_sampler_wrap(page->uWrap); - } - if (with_overrides && (atlas->overrides.wrap_v != _SG_WRAP_DEFAULT)) { - info->wrap_v = atlas->overrides.wrap_v; - } else { - info->wrap_v = _sspine_as_sampler_wrap(page->vWrap); - } - info->width = page->width; - info->height = page->height; - // NOTE: override already happened in atlas init - info->premul_alpha = page->pma != 0; - info->filename = _sspine_string(page->name); - if (info->filename.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } -} - -static void _sspine_init_shared(void) { - sg_shader_desc shd_desc; - _sspine_clear(&shd_desc, sizeof(shd_desc)); - shd_desc.attrs[0].name = "position"; - shd_desc.attrs[1].name = "texcoord0"; - shd_desc.attrs[2].name = "color0"; - shd_desc.attrs[0].sem_name = "TEXCOORD"; - shd_desc.attrs[0].sem_index = 0; - shd_desc.attrs[1].sem_name = "TEXCOORD"; - shd_desc.attrs[1].sem_index = 1; - shd_desc.attrs[2].sem_name = "TEXCOORD"; - shd_desc.attrs[2].sem_index = 2; - shd_desc.vs.uniform_blocks[0].size = sizeof(_sspine_vsparams_t); - shd_desc.vs.uniform_blocks[0].layout = SG_UNIFORMLAYOUT_STD140; - shd_desc.vs.uniform_blocks[0].uniforms[0].name = "vs_params"; - shd_desc.vs.uniform_blocks[0].uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - shd_desc.vs.uniform_blocks[0].uniforms[0].array_count = 4; - shd_desc.fs.uniform_blocks[0].size = 16; - shd_desc.fs.uniform_blocks[0].layout = SG_UNIFORMLAYOUT_STD140; - shd_desc.fs.uniform_blocks[0].uniforms[0].name = "fs_params"; - shd_desc.fs.uniform_blocks[0].uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; - shd_desc.fs.uniform_blocks[0].uniforms[0].array_count = 1; - shd_desc.fs.images[0].used = true; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; - shd_desc.fs.samplers[0].used = true; - shd_desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; - shd_desc.fs.image_sampler_pairs[0].used = true; - shd_desc.fs.image_sampler_pairs[0].image_slot = 0; - shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; - shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; - shd_desc.label = "sspine-shader"; - #if defined(SOKOL_GLCORE) - shd_desc.vs.source = (const char*)_sspine_vs_source_glsl410; - shd_desc.fs.source = (const char*)_sspine_fs_source_glsl410; - #elif defined(SOKOL_GLES3) - shd_desc.vs.source = (const char*)_sspine_vs_source_glsl300es; - shd_desc.fs.source = (const char*)_sspine_fs_source_glsl300es; - #elif defined(SOKOL_METAL) - shd_desc.vs.entry = "main0"; - shd_desc.fs.entry = "main0"; - switch (sg_query_backend()) { - case SG_BACKEND_METAL_MACOS: - shd_desc.vs.bytecode = SG_RANGE(_sspine_vs_bytecode_metal_macos); - shd_desc.fs.bytecode = SG_RANGE(_sspine_fs_bytecode_metal_macos); - break; - case SG_BACKEND_METAL_IOS: - shd_desc.vs.bytecode = SG_RANGE(_sspine_vs_bytecode_metal_ios); - shd_desc.fs.bytecode = SG_RANGE(_sspine_fs_bytecode_metal_ios); - break; - default: - shd_desc.vs.source = (const char*)_sspine_vs_source_metal_sim; - shd_desc.fs.source = (const char*)_sspine_fs_source_metal_sim; - break; - } - #elif defined(SOKOL_D3D11) - shd_desc.vs.bytecode = SG_RANGE(_sspine_vs_bytecode_hlsl4); - shd_desc.fs.bytecode = SG_RANGE(_sspine_fs_bytecode_hlsl4); - #elif defined(SOKOL_WGPU) - shd_desc.vs.source = (const char*)_sspine_vs_source_wgsl; - shd_desc.fs.source = (const char*)_sspine_fs_source_wgsl; - #else - shd_desc.vs.source = _sspine_vs_source_dummy; - shd_desc.fs.source = _sspine_fs_source_dummy; - #endif - _sspine.shd = sg_make_shader(&shd_desc); -} - -static void _sspine_destroy_shared(void) { - sg_destroy_shader(_sspine.shd); -} - -// called from inside sokol-gfx sg_commit() -static void _sspine_commit_listener_func(void* userdata) { - (void)userdata; - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine.frame_id++; -} - -static sg_commit_listener _sspine_make_commit_listener(void) { - sg_commit_listener commit_listener = { _sspine_commit_listener_func, 0 }; - return commit_listener; -} - -// ██████ ██ ██ ██████ ██ ██ ██████ -// ██ ██ ██ ██ ██ ██ ██ ██ ██ -// ██████ ██ ██ ██████ ██ ██ ██ -// ██ ██ ██ ██ ██ ██ ██ ██ -// ██ ██████ ██████ ███████ ██ ██████ -// -// >>public -SOKOL_API_IMPL void sspine_setup(const sspine_desc* desc) { - SOKOL_ASSERT(desc); - spBone_setYDown(1); - _sspine_clear(&_sspine, sizeof(_sspine)); - _sspine.init_cookie = _SSPINE_INIT_COOKIE; - _sspine.desc = _sspine_desc_defaults(desc); - _sspine_init_shared(); - // important, need to setup the frame id with a non-zero value, - // otherwise updates won't trigger in the first frame - _sspine.frame_id = 1; - _sspine_setup_context_pool(_sspine.desc.context_pool_size); - _sspine_setup_atlas_pool(_sspine.desc.atlas_pool_size); - _sspine_setup_skeleton_pool(_sspine.desc.skeleton_pool_size); - _sspine_setup_skinset_pool(_sspine.desc.skinset_pool_size); - _sspine_setup_instance_pool(_sspine.desc.instance_pool_size); - const sspine_context_desc ctx_desc = _sspine_as_context_desc(&_sspine.desc); - _sspine.def_ctx_id = sspine_make_context(&ctx_desc); - SOKOL_ASSERT(_sspine_is_default_context(_sspine.def_ctx_id)); - sspine_set_context(_sspine.def_ctx_id); - if (!sg_add_commit_listener(_sspine_make_commit_listener())) { - _SSPINE_ERROR(ADD_COMMIT_LISTENER_FAILED); - } -} - -SOKOL_API_IMPL void sspine_shutdown(void) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sg_remove_commit_listener(_sspine_make_commit_listener()); - _sspine_destroy_all_instances(); - _sspine_destroy_all_skinsets(); - _sspine_destroy_all_skeletons(); - _sspine_destroy_all_atlases(); - _sspine_destroy_all_contexts(); - _sspine_discard_instance_pool(); - _sspine_discard_skinset_pool(); - _sspine_discard_skeleton_pool(); - _sspine_discard_atlas_pool(); - _sspine_discard_context_pool(); - _sspine_destroy_shared(); - _sspine.init_cookie = 0; -} - -SOKOL_API_IMPL sspine_context sspine_make_context(const sspine_context_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_context_desc desc_def = _sspine_context_desc_defaults(desc); - sspine_context ctx_id = _sspine_alloc_context(); - _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - ctx->slot.state = _sspine_init_context(ctx, &desc_def); - SOKOL_ASSERT((ctx->slot.state == SSPINE_RESOURCESTATE_VALID) || (ctx->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (ctx->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_context(ctx); - } - } else { - ctx->slot.state = SSPINE_RESOURCESTATE_FAILED; - _SSPINE_ERROR(CONTEXT_POOL_EXHAUSTED); - } - return ctx_id; -} - -SOKOL_API_IMPL void sspine_destroy_context(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - if (_sspine_is_default_context(ctx_id)) { - _SSPINE_ERROR(CANNOT_DESTROY_DEFAULT_CONTEXT); - return; - } - _sspine_destroy_context(ctx_id); - // re-validate the current context pointer (this will return a nullptr - // if we just destroyed the current context) - _sspine.cur_ctx = _sspine_lookup_context(_sspine.cur_ctx_id.id); -} - -SOKOL_API_IMPL void sspine_set_context(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - if (_sspine_is_default_context(ctx_id)) { - _sspine.cur_ctx_id = _sspine.def_ctx_id; - } else { - _sspine.cur_ctx_id = ctx_id; - } - // this will return null if the handle isn't valid - _sspine.cur_ctx = _sspine_lookup_context(_sspine.cur_ctx_id.id); -} - -SOKOL_API_IMPL sspine_context sspine_get_context(void) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return _sspine.cur_ctx_id; -} - -SOKOL_API_IMPL sspine_context sspine_default_context(void) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return _sspine_make_context_handle(0x00010001); -} - -SOKOL_API_IMPL sspine_context_info sspine_get_context_info(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_context_info res; - _sspine_clear(&res, sizeof(res)); - const _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - res.num_vertices = ctx->vertices.next; - res.num_indices = ctx->indices.next; - res.num_commands = ctx->commands.next; - } - return res; -} - -SOKOL_API_IMPL void sspine_set_skinset(sspine_instance instance_id, sspine_skinset skinset_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - _sspine_skinset_t* skinset = _sspine_lookup_skinset(skinset_id.id); - if (_sspine_instance_and_deps_valid(instance) && _sspine_skinset_and_deps_valid(skinset) && (instance->skel.id == skinset->skel.id)) { - SOKOL_ASSERT(instance->sp_skel); - SOKOL_ASSERT(instance->sp_anim_state); - SOKOL_ASSERT(skinset->sp_skin); - spSkeleton_setSkin(instance->sp_skel, 0); - spSkeleton_setSkin(instance->sp_skel, skinset->sp_skin); - spSkeleton_setSlotsToSetupPose(instance->sp_skel); - spAnimationState_apply(instance->sp_anim_state, instance->sp_skel); - } -} - -SOKOL_API_IMPL void sspine_update_instance(sspine_instance instance_id, float delta_time) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_skel); - SOKOL_ASSERT(instance->sp_anim_state); - _sspine_rewind_triggered_events(instance); - spAnimationState_update(instance->sp_anim_state, delta_time); - spAnimationState_apply(instance->sp_anim_state, instance->sp_skel); - spSkeleton_updateWorldTransform(instance->sp_skel); - } -} - -SOKOL_API_IMPL int sspine_num_triggered_events(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT((instance->cur_triggered_event_index >= 0) && (instance->cur_triggered_event_index <= _SSPINE_MAX_TRIGGERED_EVENTS)); - return instance->cur_triggered_event_index; - } - return 0; -} - -SOKOL_API_IMPL sspine_triggered_event_info sspine_get_triggered_event_info(sspine_instance instance_id, int triggered_event_index) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_triggered_event_info res; - _sspine_clear(&res, sizeof(res)); - if (_sspine_instance_and_deps_valid(instance)) { - if ((triggered_event_index >= 0) && (triggered_event_index < instance->cur_triggered_event_index)) { - res = instance->triggered_events[triggered_event_index]; - } - } - return res; -} - -SOKOL_API_IMPL void sspine_draw_instance_in_layer(sspine_instance instance_id, int layer) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_context_t* ctx = _sspine.cur_ctx; - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (ctx && _sspine_instance_and_deps_valid(instance)) { - _sspine_draw_instance(ctx, instance, layer); - } -} - -SOKOL_API_IMPL sspine_mat4 sspine_layer_transform_to_mat4(const sspine_layer_transform* tform) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_mat4 res; - _sspine_layer_transform_to_proj(tform, res.m); - return res; -} - -SOKOL_API_IMPL void sspine_context_draw_instance_in_layer(sspine_context ctx_id, sspine_instance instance_id, int layer) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (ctx && _sspine_instance_and_deps_valid(instance)) { - _sspine_draw_instance(ctx, instance, layer); - } -} - -SOKOL_API_IMPL void sspine_draw_layer(int layer, const sspine_layer_transform* tform) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(tform); - _sspine_context_t* ctx = _sspine.cur_ctx; - if (ctx) { - _sspine_draw_layer(ctx, layer, tform); - } -} - -SOKOL_API_IMPL void sspine_context_draw_layer(sspine_context ctx_id, int layer, const sspine_layer_transform* tform) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(tform); - _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - _sspine_draw_layer(ctx, layer, tform); - } -} - -SOKOL_API_IMPL sspine_atlas sspine_make_atlas(const sspine_atlas_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_atlas_desc desc_def = _sspine_atlas_desc_defaults(desc); - sspine_atlas atlas_id = _sspine_alloc_atlas(); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - atlas->slot.state = _sspine_init_atlas(atlas, &desc_def); - SOKOL_ASSERT((atlas->slot.state == SSPINE_RESOURCESTATE_VALID) || (atlas->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (atlas->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_atlas(atlas); - } - } else { - _SSPINE_ERROR(ATLAS_POOL_EXHAUSTED); - } - return atlas_id; -} - -SOKOL_API_IMPL void sspine_destroy_atlas(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_destroy_atlas(atlas_id); -} - -SOKOL_API_IMPL sspine_skeleton sspine_make_skeleton(const sspine_skeleton_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_skeleton_desc desc_def = _sspine_skeleton_desc_defaults(desc); - sspine_skeleton skeleton_id = _sspine_alloc_skeleton(); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (skeleton) { - skeleton->slot.state = _sspine_init_skeleton(skeleton, &desc_def); - SOKOL_ASSERT((skeleton->slot.state == SSPINE_RESOURCESTATE_VALID) || (skeleton->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (skeleton->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_skeleton(skeleton); - } - } else { - _SSPINE_ERROR(SKELETON_POOL_EXHAUSTED); - } - return skeleton_id; -} - -SOKOL_API_IMPL void sspine_destroy_skeleton(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_destroy_skeleton(skeleton_id); -} - -SOKOL_API_IMPL sspine_skinset sspine_make_skinset(const sspine_skinset_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_skinset_desc desc_def = _sspine_skinset_desc_defaults(desc); - sspine_skinset skinset_id = _sspine_alloc_skinset(); - _sspine_skinset_t* skinset = _sspine_lookup_skinset(skinset_id.id); - if (skinset) { - skinset->slot.state = _sspine_init_skinset(skinset, &desc_def); - SOKOL_ASSERT((skinset->slot.state == SSPINE_RESOURCESTATE_VALID) || (skinset->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (skinset->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_skinset(skinset); - } - } else { - _SSPINE_ERROR(SKINSET_POOL_EXHAUSTED); - } - return skinset_id; -} - -SOKOL_API_IMPL void sspine_destroy_skinset(sspine_skinset skinset_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_destroy_skinset(skinset_id); -} - -SOKOL_API_IMPL sspine_instance sspine_make_instance(const sspine_instance_desc* desc) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(desc); - const sspine_instance_desc desc_def = _sspine_instance_desc_defaults(desc); - sspine_instance instance_id = _sspine_alloc_instance(); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - instance->slot.state = _sspine_init_instance(instance, &desc_def); - SOKOL_ASSERT((instance->slot.state == SSPINE_RESOURCESTATE_VALID) || (instance->slot.state == SSPINE_RESOURCESTATE_FAILED)); - if (instance->slot.state == SSPINE_RESOURCESTATE_FAILED) { - _sspine_deinit_instance(instance); - } - } else { - _SSPINE_ERROR(INSTANCE_POOL_EXHAUSTED); - } - return instance_id; -} - -SOKOL_API_IMPL void sspine_destroy_instance(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_destroy_instance(instance_id); -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_context_resource_state(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); - if (ctx) { - return ctx->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_atlas_resource_state(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - return atlas->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_skeleton_resource_state(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (skeleton) { - return skeleton->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_skinset_resource_state(sspine_skinset skinset_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_skinset_t* skinset = _sspine_lookup_skinset(skinset_id.id); - if (skinset) { - return skinset->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL sspine_resource_state sspine_get_instance_resource_state(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - const _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - return instance->slot.state; - } else { - return SSPINE_RESOURCESTATE_INVALID; - } -} - -SOKOL_API_IMPL bool sspine_context_valid(sspine_context ctx_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_context_resource_state(ctx_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL bool sspine_atlas_valid(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_atlas_resource_state(atlas_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL bool sspine_skeleton_valid(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_skeleton_resource_state(skeleton_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL bool sspine_skinset_valid(sspine_skinset skinset_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_skinset_resource_state(skinset_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL bool sspine_instance_valid(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - return sspine_get_instance_resource_state(instance_id) == SSPINE_RESOURCESTATE_VALID; -} - -SOKOL_API_IMPL sspine_atlas sspine_get_skeleton_atlas(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - sspine_atlas res; - _sspine_clear(&res, sizeof(res)); - if (skeleton) { - res.id = skeleton->atlas.id; - } - return res; -} - -SOKOL_API_IMPL sspine_skeleton sspine_get_instance_skeleton(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_skeleton res; - _sspine_clear(&res, sizeof(res)); - if (instance) { - res.id = instance->skel.id; - } - return res; -} - -SOKOL_API_IMPL int sspine_num_images(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - return atlas->num_pages; - } - return 0; -} - -SOKOL_API_IMPL sspine_image sspine_image_by_index(sspine_atlas atlas_id, int index) { - return _sspine_image(atlas_id.id, index); -} - -SOKOL_API_IMPL bool sspine_image_valid(sspine_image image) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(image.atlas_id); - return atlas && (image.index >= 0) && (image.index < atlas->num_pages); -} - -SOKOL_API_IMPL bool sspine_image_equal(sspine_image first, sspine_image second) { - return (first.atlas_id == second.atlas_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_image_info sspine_get_image_info(sspine_image image) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(image.atlas_id); - sspine_image_info img_info; - _sspine_clear(&img_info, sizeof(img_info)); - if (atlas && (image.index >= 0) && (image.index < atlas->num_pages)) { - _sspine_init_image_info(atlas, image.index, &img_info, true); - } - return img_info; -} - -SOKOL_API_IMPL int sspine_num_atlas_pages(sspine_atlas atlas_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(atlas_id.id); - if (atlas) { - return atlas->num_pages; - } else { - return 0; - } -} - -SOKOL_API_IMPL sspine_atlas_page sspine_atlas_page_by_index(sspine_atlas atlas_id, int index) { - return _sspine_atlas_page(atlas_id.id, index); -} - -SOKOL_API_IMPL bool sspine_atlas_page_valid(sspine_atlas_page page) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_atlas_t* atlas = _sspine_lookup_atlas(page.atlas_id); - if (atlas) { - return (page.index >= 0) && (page.index < atlas->num_pages); - } - return false; -} - -SOKOL_API_IMPL bool sspine_atlas_page_equal(sspine_atlas_page first, sspine_atlas_page second) { - return (first.atlas_id == second.atlas_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_atlas_page_info sspine_get_atlas_page_info(sspine_atlas_page page) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_atlas_page_info res; - _sspine_clear(&res, sizeof(res)); - const spAtlasPage* sp_page = _sspine_lookup_atlas_page(page.atlas_id, page.index); - if (sp_page) { - // at this point, atlas is guaranteed to be valid - const _sspine_atlas_t* atlas = _sspine_lookup_atlas(page.atlas_id); - res.valid = true; - res.atlas.id = page.atlas_id; - // write image info without overrides - _sspine_init_image_info(atlas, page.index, &res.image, false); - // ...and provide the overrides separately - res.overrides = atlas->overrides; - } - return res; -} - -SOKOL_API_IMPL void sspine_set_position(sspine_instance instance_id, sspine_vec2 position) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_skel); - instance->sp_skel->x = position.x; - instance->sp_skel->y = position.y; - } -} - -SOKOL_API_IMPL void sspine_set_scale(sspine_instance instance_id, sspine_vec2 scale) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - instance->sp_skel->scaleX = scale.x; - instance->sp_skel->scaleY = scale.y; - } -} - -SOKOL_API_IMPL void sspine_set_color(sspine_instance instance_id, sspine_color color) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - instance->sp_skel->color.r = color.r; - instance->sp_skel->color.g = color.g; - instance->sp_skel->color.b = color.b; - instance->sp_skel->color.a = color.a; - } -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_position(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_vec2 v = { 0.0f, 0.0f }; - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - v.x = instance->sp_skel->x; - v.y = instance->sp_skel->y; - } - return v; -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_scale(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_vec2 v = { 0.0f, 0.0f }; - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - v.x = instance->sp_skel->scaleX; - v.y = instance->sp_skel->scaleY; - } - return v; -} - -SOKOL_API_IMPL sspine_color sspine_get_color(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - sspine_color c = { 0.0f, 0.0f, 0.0f, 0.0f }; - if (instance) { - SOKOL_ASSERT(instance->sp_skel); - c.r = instance->sp_skel->color.r; - c.g = instance->sp_skel->color.g; - c.b = instance->sp_skel->color.b; - c.a = instance->sp_skel->color.a; - } - return c; -} - -SOKOL_API_IMPL int sspine_num_anims(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->animationsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_anim sspine_anim_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - // NOTE: there's a spSkeletonData_findAnimation function, but that doesn't - // give us access to the index, so we'll need to do the loop ourselves - SOKOL_ASSERT(skeleton->sp_skel_data); - const spSkeletonData* sp_skel_data = skeleton->sp_skel_data; - const int num_anims = sp_skel_data->animationsCount; - SOKOL_ASSERT(sp_skel_data->animations); - for (int i = 0; i < num_anims; i++) { - SOKOL_ASSERT(sp_skel_data->animations[i]); - SOKOL_ASSERT(sp_skel_data->animations[i]->name); - if (0 == strcmp(sp_skel_data->animations[i]->name, name)) { - return _sspine_anim(skeleton_id.id, i); - } - } - } - return _sspine_anim(0, 0); -} - -SOKOL_API_IMPL sspine_anim sspine_anim_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_anim(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_anim_valid(sspine_anim anim) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(anim.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (anim.index >= 0) && (anim.index < skeleton->sp_skel_data->animationsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_anim_equal(sspine_anim first, sspine_anim second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_anim_info sspine_get_anim_info(sspine_anim anim) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_anim_info res; - _sspine_clear(&res, sizeof(res)); - const spAnimation* sp_anim = _sspine_lookup_skeleton_anim(anim.skeleton_id, anim.index); - if (sp_anim) { - res.valid = true; - res.index = anim.index; - res.duration = sp_anim->duration; - res.name = _sspine_string(sp_anim->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL void sspine_clear_animation_tracks(sspine_instance instance_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_clearTracks(instance->sp_anim_state); - } -} - -SOKOL_API_IMPL void sspine_clear_animation_track(sspine_instance instance_id, int track_index) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_clearTrack(instance->sp_anim_state, track_index); - } -} - -SOKOL_API_IMPL void sspine_set_animation(sspine_instance instance_id, sspine_anim anim, int track_index, bool loop) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spAnimation* sp_anim = _sspine_lookup_instance_anim(instance_id.id, anim.skeleton_id, anim.index); - if (sp_anim) { - // NOTE: at this point, instance is guaranteed to be valid - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - SOKOL_ASSERT(instance); - spAnimationState_setAnimation(instance->sp_anim_state, track_index, sp_anim, loop?1:0); - } -} - -SOKOL_API_IMPL void sspine_add_animation(sspine_instance instance_id, sspine_anim anim, int track_index, bool loop, float delay) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spAnimation* sp_anim = _sspine_lookup_instance_anim(instance_id.id, anim.skeleton_id, anim.index); - if (sp_anim) { - // NOTE: at this point, instance is guaranteed to be valid - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - SOKOL_ASSERT(instance); - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_addAnimation(instance->sp_anim_state, track_index, sp_anim, loop?1:0, delay); - } -} - -SOKOL_API_IMPL void sspine_set_empty_animation(sspine_instance instance_id, int track_index, float mix_duration) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_setEmptyAnimation(instance->sp_anim_state, track_index, mix_duration); - } -} - -SOKOL_API_IMPL void sspine_add_empty_animation(sspine_instance instance_id, int track_index, float mix_duration, float delay) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance)) { - SOKOL_ASSERT(instance->sp_anim_state); - spAnimationState_addEmptyAnimation(instance->sp_anim_state, track_index, mix_duration, delay); - } -} - -SOKOL_API_IMPL int sspine_num_bones(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->bonesCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_bone sspine_bone_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - spBoneData* sp_bone_data = spSkeletonData_findBone(skeleton->sp_skel_data, name); - if (sp_bone_data) { - return _sspine_bone(skeleton_id.id, sp_bone_data->index); - } - } - return _sspine_bone(0, 0); -} - -SOKOL_API_IMPL sspine_bone sspine_bone_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_bone(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_bone_valid(sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(bone.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (bone.index >= 0) && (bone.index < skeleton->sp_skel_data->bonesCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_bone_equal(sspine_bone first, sspine_bone second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_bone_info sspine_get_bone_info(sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_bone_info res; - _sspine_clear(&res, sizeof(res)); - const spBoneData* sp_bone_data = _sspine_lookup_bone_data(bone.skeleton_id, bone.index); - if (sp_bone_data) { - SOKOL_ASSERT(sp_bone_data->index == bone.index); - SOKOL_ASSERT(sp_bone_data->name); - res.valid = true; - res.index = sp_bone_data->index; - if (sp_bone_data->parent) { - res.parent_bone = _sspine_bone(bone.skeleton_id, sp_bone_data->parent->index); - } - res.length = sp_bone_data->length; - res.pose.position.x = sp_bone_data->x; - res.pose.position.y = sp_bone_data->y; - res.pose.rotation = sp_bone_data->rotation; - res.pose.scale.x = sp_bone_data->scaleX; - res.pose.scale.y = sp_bone_data->scaleY; - res.pose.shear.x = sp_bone_data->shearX; - res.pose.shear.y = sp_bone_data->shearY; - res.color.r = sp_bone_data->color.r; - res.color.g = sp_bone_data->color.g; - res.color.b = sp_bone_data->color.b; - res.color.a = sp_bone_data->color.a; - res.name = _sspine_string(sp_bone_data->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL void sspine_set_bone_transform(sspine_instance instance_id, sspine_bone bone, const sspine_bone_transform* transform) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(transform); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->x = transform->position.x; - sp_bone->y = transform->position.y; - sp_bone->rotation = transform->rotation; - sp_bone->scaleX = transform->scale.x; - sp_bone->scaleY = transform->scale.y; - sp_bone->shearX = transform->shear.x; - sp_bone->shearY = transform->shear.y; - } -} - -SOKOL_API_IMPL void sspine_set_bone_position(sspine_instance instance_id, sspine_bone bone, sspine_vec2 position) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->x = position.x; - sp_bone->y = position.y; - } -} - -SOKOL_API_IMPL void sspine_set_bone_rotation(sspine_instance instance_id, sspine_bone bone, float rotation) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->rotation = rotation; - } -} - -SOKOL_API_IMPL void sspine_set_bone_scale(sspine_instance instance_id, sspine_bone bone, sspine_vec2 scale) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->scaleX = scale.x; - sp_bone->scaleY = scale.y; - } -} - -SOKOL_API_IMPL void sspine_set_bone_shear(sspine_instance instance_id, sspine_bone bone, sspine_vec2 shear) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - sp_bone->shearX = shear.x; - sp_bone->shearY = shear.y; - } -} - -SOKOL_API_IMPL sspine_bone_transform sspine_get_bone_transform(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_bone_transform res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.position.x = sp_bone->x; - res.position.y = sp_bone->y; - res.rotation = sp_bone->rotation; - res.scale.x = sp_bone->scaleX; - res.scale.y = sp_bone->scaleY; - res.shear.x = sp_bone->shearX; - res.shear.y = sp_bone->shearY; - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_bone_position(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.x = sp_bone->x; - res.y = sp_bone->y; - } - return res; -} - -SOKOL_API_IMPL float sspine_get_bone_rotation(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - return sp_bone->rotation; - } else { - return 0.0f; - } -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_bone_scale(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.x = sp_bone->scaleX; - res.y = sp_bone->scaleY; - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_bone_shear(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.x = sp_bone->shearX; - res.y = sp_bone->shearY; - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_get_bone_world_position(sspine_instance instance_id, sspine_bone bone) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - res.x = sp_bone->worldX; - res.y = sp_bone->worldY; - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_bone_local_to_world(sspine_instance instance_id, sspine_bone bone, sspine_vec2 local_pos) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - spBone_localToWorld(sp_bone, local_pos.x, local_pos.y, &res.x, &res.y); - } - return res; -} - -SOKOL_API_IMPL sspine_vec2 sspine_bone_world_to_local(sspine_instance instance_id, sspine_bone bone, sspine_vec2 world_pos) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_vec2 res; - _sspine_clear(&res, sizeof(res)); - spBone* sp_bone = _sspine_lookup_bone(instance_id.id, bone.skeleton_id, bone.index); - if (sp_bone) { - spBone_worldToLocal(sp_bone, world_pos.x, world_pos.y, &res.x, &res.y); - } - return res; -} - -SOKOL_API_IMPL int sspine_num_slots(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->slotsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_slot sspine_slot_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - spSlotData* sp_slot_data = spSkeletonData_findSlot(skeleton->sp_skel_data, name); - if (sp_slot_data) { - return _sspine_slot(skeleton_id.id, sp_slot_data->index); - } - } - return _sspine_slot(0, 0); -} - -SOKOL_API_IMPL sspine_slot sspine_slot_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_slot(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_slot_valid(sspine_slot slot) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(slot.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (slot.index >= 0) && (slot.index < skeleton->sp_skel_data->slotsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_slot_equal(sspine_slot first, sspine_slot second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_slot_info sspine_get_slot_info(sspine_slot slot) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_slot_info res; - _sspine_clear(&res, sizeof(res)); - const spSlotData* sp_slot_data = _sspine_lookup_slot_data(slot.skeleton_id, slot.index); - if (sp_slot_data) { - SOKOL_ASSERT(sp_slot_data->index == slot.index); - SOKOL_ASSERT(sp_slot_data->name); - SOKOL_ASSERT(sp_slot_data->boneData); - res.valid = true; - res.index = sp_slot_data->index; - res.bone = _sspine_bone(slot.skeleton_id, sp_slot_data->boneData->index); - res.color.r = sp_slot_data->color.r; - res.color.g = sp_slot_data->color.g; - res.color.b = sp_slot_data->color.b; - res.color.a = sp_slot_data->color.a; - res.attachment_name = _sspine_string(sp_slot_data->attachmentName); - if (res.attachment_name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - res.name = _sspine_string(sp_slot_data->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL void sspine_set_slot_color(sspine_instance instance_id, sspine_slot slot, sspine_color color) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spSlot* sp_slot = _sspine_lookup_slot(instance_id.id, slot.skeleton_id, slot.index); - if (sp_slot) { - sp_slot->color.r = color.r; - sp_slot->color.g = color.g; - sp_slot->color.b = color.b; - sp_slot->color.a = color.a; - } -} - -SOKOL_API_IMPL sspine_color sspine_get_slot_color(sspine_instance instance_id, sspine_slot slot) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_color color; - _sspine_clear(&color, sizeof(color)); - spSlot* sp_slot = _sspine_lookup_slot(instance_id.id, slot.skeleton_id, slot.index); - if (sp_slot) { - color.r = sp_slot->color.r; - color.g = sp_slot->color.g; - color.b = sp_slot->color.b; - color.a = sp_slot->color.a; - } - return color; -} - -SOKOL_API_IMPL int sspine_num_events(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->eventsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_event sspine_event_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - SOKOL_ASSERT(skeleton->sp_skel_data->events); - // spEventData has no embedded index, so we need to loop over the events - for (int i = 0; i < skeleton->sp_skel_data->eventsCount; i++) { - SOKOL_ASSERT(skeleton->sp_skel_data->events[i]); - SOKOL_ASSERT(skeleton->sp_skel_data->events[i]->name); - if (0 == strcmp(skeleton->sp_skel_data->events[i]->name, name)) { - return _sspine_event(skeleton_id.id, i); - } - } - } - return _sspine_event(0, 0); -} - -SOKOL_API_IMPL sspine_event sspine_event_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_event(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_event_valid(sspine_event event) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(event.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (event.index >= 0) && (event.index < skeleton->sp_skel_data->eventsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_event_equal(sspine_event first, sspine_event second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_event_info sspine_get_event_info(sspine_event event) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_event_info res; - _sspine_clear(&res, sizeof(res)); - const spEventData* sp_event_data = _sspine_lookup_event_data(event.skeleton_id, event.index); - if (sp_event_data) { - res.valid = true; - res.index = event.index; - res.int_value = sp_event_data->intValue; - res.float_value = sp_event_data->floatValue; - res.volume = sp_event_data->volume; - res.balance = sp_event_data->balance; - res.name = _sspine_string(sp_event_data->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - res.string_value = _sspine_string(sp_event_data->stringValue); - if (res.string_value.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - res.audio_path = _sspine_string(sp_event_data->audioPath); - if (res.audio_path.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL int sspine_num_iktargets(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->ikConstraintsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_iktarget sspine_iktarget_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - SOKOL_ASSERT(skeleton->sp_skel_data->ikConstraints); - // spIkConstraintData has no embedded index, so we need to loop over the events - for (int i = 0; i < skeleton->sp_skel_data->ikConstraintsCount; i++) { - SOKOL_ASSERT(skeleton->sp_skel_data->ikConstraints[i]); - SOKOL_ASSERT(skeleton->sp_skel_data->ikConstraints[i]->name); - if (0 == strcmp(skeleton->sp_skel_data->ikConstraints[i]->name, name)) { - return _sspine_iktarget(skeleton_id.id, i); - } - } - } - return _sspine_iktarget(0, 0); -} - -SOKOL_API_IMPL sspine_iktarget sspine_iktarget_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_iktarget(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_iktarget_valid(sspine_iktarget iktarget) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(iktarget.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (iktarget.index >= 0) && (iktarget.index < skeleton->sp_skel_data->ikConstraintsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_iktarget_equal(sspine_iktarget first, sspine_iktarget second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_iktarget_info sspine_get_iktarget_info(sspine_iktarget iktarget) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_iktarget_info res; - _sspine_clear(&res, sizeof(res)); - const spIkConstraintData* ik_data = _sspine_lookup_ikconstraint_data(iktarget.skeleton_id, iktarget.index); - if (ik_data) { - res.valid = true; - res.index = iktarget.index; - res.target_bone = _sspine_bone(iktarget.skeleton_id, ik_data->target->index); - res.name = _sspine_string(ik_data->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_API_IMPL void sspine_set_iktarget_world_pos(sspine_instance instance_id, sspine_iktarget iktarget, sspine_vec2 world_pos) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - spIkConstraint* ik_data = _sspine_lookup_ikconstraint(instance_id.id, iktarget.skeleton_id, iktarget.index); - if (ik_data) { - spBone* bone = ik_data->target; - spBone* parent_bone = bone->parent; - if (parent_bone) { - spBone_worldToLocal(parent_bone, world_pos.x, world_pos.y, &bone->x, &bone->y); - } - } -} - -SOKOL_API_IMPL int sspine_num_skins(sspine_skeleton skeleton_id) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return skeleton->sp_skel_data->skinsCount; - } - return 0; -} - -SOKOL_API_IMPL sspine_skin sspine_skin_by_name(sspine_skeleton skeleton_id, const char* name) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - SOKOL_ASSERT(name); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skeleton_id.id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - SOKOL_ASSERT(skeleton->sp_skel_data->skins); - // spSkin has no embedded index, so we need to loop over the skins - for (int i = 0; i < skeleton->sp_skel_data->skinsCount; i++) { - SOKOL_ASSERT(skeleton->sp_skel_data->skins[i]); - SOKOL_ASSERT(skeleton->sp_skel_data->skins[i]->name); - if (0 == strcmp(skeleton->sp_skel_data->skins[i]->name, name)) { - return _sspine_skin(skeleton_id.id, i); - } - } - } - return _sspine_skin(0, 0); -} - -SOKOL_API_IMPL sspine_skin sspine_skin_by_index(sspine_skeleton skeleton_id, int index) { - return _sspine_skin(skeleton_id.id, index); -} - -SOKOL_API_IMPL bool sspine_skin_valid(sspine_skin skin) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_skeleton_t* skeleton = _sspine_lookup_skeleton(skin.skeleton_id); - if (_sspine_skeleton_and_deps_valid(skeleton)) { - SOKOL_ASSERT(skeleton->sp_skel_data); - return (skin.index >= 0) && (skin.index < skeleton->sp_skel_data->skinsCount); - } - return false; -} - -SOKOL_API_IMPL bool sspine_skin_equal(sspine_skin first, sspine_skin second) { - return (first.skeleton_id == second.skeleton_id) && (first.index == second.index); -} - -SOKOL_API_IMPL sspine_skin_info sspine_get_skin_info(sspine_skin skin) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - sspine_skin_info res; - _sspine_clear(&res, sizeof(res)); - const spSkin* sp_skin = _sspine_lookup_skin(skin.skeleton_id, skin.index); - if (sp_skin) { - res.valid = true; - res.index = skin.index; - res.name = _sspine_string(sp_skin->name); - if (res.name.truncated) { - _SSPINE_WARN(STRING_TRUNCATED); - } - } - return res; -} - -SOKOL_SPINE_API_DECL void sspine_set_skin(sspine_instance instance_id, sspine_skin skin) { - SOKOL_ASSERT(_SSPINE_INIT_COOKIE == _sspine.init_cookie); - _sspine_instance_t* instance = _sspine_lookup_instance(instance_id.id); - if (_sspine_instance_and_deps_valid(instance) && (instance->skel.id == skin.skeleton_id)) { - SOKOL_ASSERT(instance->sp_skel); - SOKOL_ASSERT(instance->sp_anim_state); - // clear any currently set skinset - instance->skinset.id = SSPINE_INVALID_ID; - instance->skinset.ptr = 0; - spSkin* sp_skin = _sspine_lookup_skin(skin.skeleton_id, skin.index); - if (sp_skin) { - spSkeleton_setSkin(instance->sp_skel, 0); - spSkeleton_setSkin(instance->sp_skel, sp_skin); - spSkeleton_setSlotsToSetupPose(instance->sp_skel); - spAnimationState_apply(instance->sp_anim_state, instance->sp_skel); - } - } -} - -#endif // SOKOL_SPINE_IMPL -#endif // SOKOL_SPINE_INCLUDED diff --git a/source/tinydir.h b/source/tinydir.h deleted file mode 100644 index d7f46689..00000000 --- a/source/tinydir.h +++ /dev/null @@ -1,848 +0,0 @@ -/* -Copyright (c) 2013-2021, tinydir authors: -- Cong Xu -- Lautis Sun -- Baudouin Feildel -- Andargor -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef TINYDIR_H -#define TINYDIR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if ((defined _UNICODE) && !(defined UNICODE)) -#define UNICODE -#endif - -#if ((defined UNICODE) && !(defined _UNICODE)) -#define _UNICODE -#endif - -#include -#include -#include -#ifdef _MSC_VER -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# include -# pragma warning(push) -# pragma warning (disable : 4996) -#else -# include -# include -# include -# include -#endif -#ifdef __MINGW32__ -# include -#endif - - -/* types */ - -/* Windows UNICODE wide character support */ -#if defined _MSC_VER || defined __MINGW32__ -# define _tinydir_char_t TCHAR -# define TINYDIR_STRING(s) _TEXT(s) -# define _tinydir_strlen _tcslen -# define _tinydir_strcpy _tcscpy -# define _tinydir_strcat _tcscat -# define _tinydir_strcmp _tcscmp -# define _tinydir_strrchr _tcsrchr -# define _tinydir_strncmp _tcsncmp -#else -# define _tinydir_char_t char -# define TINYDIR_STRING(s) s -# define _tinydir_strlen strlen -# define _tinydir_strcpy strcpy -# define _tinydir_strcat strcat -# define _tinydir_strcmp strcmp -# define _tinydir_strrchr strrchr -# define _tinydir_strncmp strncmp -#endif - -#if (defined _MSC_VER || defined __MINGW32__) -# include -# define _TINYDIR_PATH_MAX MAX_PATH -#elif defined __linux__ -# include -# ifdef PATH_MAX -# define _TINYDIR_PATH_MAX PATH_MAX -# endif -#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) -# include -# if defined(BSD) -# include -# ifdef PATH_MAX -# define _TINYDIR_PATH_MAX PATH_MAX -# endif -# endif -#endif - -#ifndef _TINYDIR_PATH_MAX -#define _TINYDIR_PATH_MAX 4096 -#endif - -#ifdef _MSC_VER -/* extra chars for the "\\*" mask */ -# define _TINYDIR_PATH_EXTRA 2 -#else -# define _TINYDIR_PATH_EXTRA 0 -#endif - -#define _TINYDIR_FILENAME_MAX 256 - -#if (defined _MSC_VER || defined __MINGW32__) -#define _TINYDIR_DRIVE_MAX 3 -#endif - -#ifdef _MSC_VER -# define _TINYDIR_FUNC static __inline -#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# define _TINYDIR_FUNC static __inline__ -#elif defined(__cplusplus) -# define _TINYDIR_FUNC static inline -#elif defined(__GNUC__) -/* Suppress unused function warning */ -# define _TINYDIR_FUNC __attribute__((unused)) static -#else -# define _TINYDIR_FUNC static -#endif - -#if defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86) -#ifdef _MSC_VER -# define _TINYDIR_CDECL __cdecl -#else -# define _TINYDIR_CDECL __attribute__((cdecl)) -#endif -#else -# define _TINYDIR_CDECL -#endif - -/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */ -#ifdef TINYDIR_USE_READDIR_R - -/* readdir_r is a POSIX-only function, and may not be available under various - * environments/settings, e.g. MinGW. Use readdir fallback */ -#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\ - _POSIX_SOURCE -# define _TINYDIR_HAS_READDIR_R -#endif -#if _POSIX_C_SOURCE >= 200112L -# define _TINYDIR_HAS_FPATHCONF -# include -#endif -#if _BSD_SOURCE || _SVID_SOURCE || \ - (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) -# define _TINYDIR_HAS_DIRFD -# include -#endif -#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\ - defined _PC_NAME_MAX -# define _TINYDIR_USE_FPATHCONF -#endif -#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\ - !(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX) -# define _TINYDIR_USE_READDIR -#endif - -/* Use readdir by default */ -#else -# define _TINYDIR_USE_READDIR -#endif - -/* MINGW32 has two versions of dirent, ASCII and UNICODE*/ -#ifndef _MSC_VER -#if (defined __MINGW32__) && (defined _UNICODE) -#define _TINYDIR_DIR _WDIR -#define _tinydir_dirent _wdirent -#define _tinydir_opendir _wopendir -#define _tinydir_readdir _wreaddir -#define _tinydir_closedir _wclosedir -#else -#define _TINYDIR_DIR DIR -#define _tinydir_dirent dirent -#define _tinydir_opendir opendir -#define _tinydir_readdir readdir -#define _tinydir_closedir closedir -#endif -#endif - -/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */ -#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE) -#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE) -#else -#error "Either define both alloc and free or none of them!" -#endif - -#if !defined(_TINYDIR_MALLOC) - #define _TINYDIR_MALLOC(_size) malloc(_size) - #define _TINYDIR_FREE(_ptr) free(_ptr) -#endif /* !defined(_TINYDIR_MALLOC) */ - -typedef struct tinydir_file -{ - _tinydir_char_t path[_TINYDIR_PATH_MAX]; - _tinydir_char_t name[_TINYDIR_FILENAME_MAX]; - _tinydir_char_t *extension; - int is_dir; - int is_reg; - -#ifndef _MSC_VER -#ifdef __MINGW32__ - struct _stat _s; -#else - struct stat _s; -#endif -#endif -} tinydir_file; - -typedef struct tinydir_dir -{ - _tinydir_char_t path[_TINYDIR_PATH_MAX]; - int has_next; - size_t n_files; - - tinydir_file *_files; -#ifdef _MSC_VER - HANDLE _h; - WIN32_FIND_DATA _f; -#else - _TINYDIR_DIR *_d; - struct _tinydir_dirent *_e; -#ifndef _TINYDIR_USE_READDIR - struct _tinydir_dirent *_ep; -#endif -#endif -} tinydir_dir; - - -/* declarations */ - -_TINYDIR_FUNC -int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path); -_TINYDIR_FUNC -int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path); -_TINYDIR_FUNC -void tinydir_close(tinydir_dir *dir); - -_TINYDIR_FUNC -int tinydir_next(tinydir_dir *dir); -_TINYDIR_FUNC -int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file); -_TINYDIR_FUNC -int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i); -_TINYDIR_FUNC -int tinydir_open_subdir_n(tinydir_dir *dir, size_t i); - -_TINYDIR_FUNC -int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path); -_TINYDIR_FUNC -void _tinydir_get_ext(tinydir_file *file); -_TINYDIR_FUNC -int _TINYDIR_CDECL _tinydir_file_cmp(const void *a, const void *b); -#ifndef _MSC_VER -#ifndef _TINYDIR_USE_READDIR -_TINYDIR_FUNC -size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp); -#endif -#endif - - -/* definitions*/ - -_TINYDIR_FUNC -int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path) -{ -#ifndef _MSC_VER -#ifndef _TINYDIR_USE_READDIR - int error; - int size; /* using int size */ -#endif -#else - _tinydir_char_t path_buf[_TINYDIR_PATH_MAX]; -#endif - _tinydir_char_t *pathp; - - if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0) - { - errno = EINVAL; - return -1; - } - if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) - { - errno = ENAMETOOLONG; - return -1; - } - - /* initialise dir */ - dir->_files = NULL; -#ifdef _MSC_VER - dir->_h = INVALID_HANDLE_VALUE; -#else - dir->_d = NULL; -#ifndef _TINYDIR_USE_READDIR - dir->_ep = NULL; -#endif -#endif - tinydir_close(dir); - - _tinydir_strcpy(dir->path, path); - /* Remove trailing slashes */ - pathp = &dir->path[_tinydir_strlen(dir->path) - 1]; - while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/'))) - { - *pathp = TINYDIR_STRING('\0'); - pathp++; - } -#ifdef _MSC_VER - _tinydir_strcpy(path_buf, dir->path); - _tinydir_strcat(path_buf, TINYDIR_STRING("\\*")); -#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) - dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0); -#else - dir->_h = FindFirstFile(path_buf, &dir->_f); -#endif - if (dir->_h == INVALID_HANDLE_VALUE) - { - errno = ENOENT; -#else - dir->_d = _tinydir_opendir(path); - if (dir->_d == NULL) - { -#endif - goto bail; - } - - /* read first file */ - dir->has_next = 1; -#ifndef _MSC_VER -#ifdef _TINYDIR_USE_READDIR - dir->_e = _tinydir_readdir(dir->_d); -#else - /* allocate dirent buffer for readdir_r */ - size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */ - if (size == -1) return -1; - dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size); - if (dir->_ep == NULL) return -1; - - error = readdir_r(dir->_d, dir->_ep, &dir->_e); - if (error != 0) return -1; -#endif - if (dir->_e == NULL) - { - dir->has_next = 0; - } -#endif - - return 0; - -bail: - tinydir_close(dir); - return -1; -} - -_TINYDIR_FUNC -int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path) -{ - /* Count the number of files first, to pre-allocate the files array */ - size_t n_files = 0; - if (tinydir_open(dir, path) == -1) - { - return -1; - } - while (dir->has_next) - { - n_files++; - if (tinydir_next(dir) == -1) - { - goto bail; - } - } - tinydir_close(dir); - - if (n_files == 0 || tinydir_open(dir, path) == -1) - { - return -1; - } - - dir->n_files = 0; - dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files); - if (dir->_files == NULL) - { - goto bail; - } - while (dir->has_next) - { - tinydir_file *p_file; - dir->n_files++; - - p_file = &dir->_files[dir->n_files - 1]; - if (tinydir_readfile(dir, p_file) == -1) - { - goto bail; - } - - if (tinydir_next(dir) == -1) - { - goto bail; - } - - /* Just in case the number of files has changed between the first and - second reads, terminate without writing into unallocated memory */ - if (dir->n_files == n_files) - { - break; - } - } - - qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp); - - return 0; - -bail: - tinydir_close(dir); - return -1; -} - -_TINYDIR_FUNC -void tinydir_close(tinydir_dir *dir) -{ - if (dir == NULL) - { - return; - } - - memset(dir->path, 0, sizeof(dir->path)); - dir->has_next = 0; - dir->n_files = 0; - _TINYDIR_FREE(dir->_files); - dir->_files = NULL; -#ifdef _MSC_VER - if (dir->_h != INVALID_HANDLE_VALUE) - { - FindClose(dir->_h); - } - dir->_h = INVALID_HANDLE_VALUE; -#else - if (dir->_d) - { - _tinydir_closedir(dir->_d); - } - dir->_d = NULL; - dir->_e = NULL; -#ifndef _TINYDIR_USE_READDIR - _TINYDIR_FREE(dir->_ep); - dir->_ep = NULL; -#endif -#endif -} - -_TINYDIR_FUNC -int tinydir_next(tinydir_dir *dir) -{ - if (dir == NULL) - { - errno = EINVAL; - return -1; - } - if (!dir->has_next) - { - errno = ENOENT; - return -1; - } - -#ifdef _MSC_VER - if (FindNextFile(dir->_h, &dir->_f) == 0) -#else -#ifdef _TINYDIR_USE_READDIR - dir->_e = _tinydir_readdir(dir->_d); -#else - if (dir->_ep == NULL) - { - return -1; - } - if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0) - { - return -1; - } -#endif - if (dir->_e == NULL) -#endif - { - dir->has_next = 0; -#ifdef _MSC_VER - if (GetLastError() != ERROR_SUCCESS && - GetLastError() != ERROR_NO_MORE_FILES) - { - tinydir_close(dir); - errno = EIO; - return -1; - } -#endif - } - - return 0; -} - -_TINYDIR_FUNC -int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file) -{ - const _tinydir_char_t *filename; - if (dir == NULL || file == NULL) - { - errno = EINVAL; - return -1; - } -#ifdef _MSC_VER - if (dir->_h == INVALID_HANDLE_VALUE) -#else - if (dir->_e == NULL) -#endif - { - errno = ENOENT; - return -1; - } - filename = -#ifdef _MSC_VER - dir->_f.cFileName; -#else - dir->_e->d_name; -#endif - if (_tinydir_strlen(dir->path) + - _tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >= - _TINYDIR_PATH_MAX) - { - /* the path for the file will be too long */ - errno = ENAMETOOLONG; - return -1; - } - if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX) - { - errno = ENAMETOOLONG; - return -1; - } - - _tinydir_strcpy(file->path, dir->path); - if (_tinydir_strcmp(dir->path, TINYDIR_STRING("/")) != 0) - _tinydir_strcat(file->path, TINYDIR_STRING("/")); - _tinydir_strcpy(file->name, filename); - _tinydir_strcat(file->path, filename); -#ifndef _MSC_VER -#ifdef __MINGW32__ - if (_tstat( -#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \ - || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \ - || ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ - || ((defined __APPLE__) && (defined __MACH__)) \ - || (defined BSD) - if (lstat( -#else - if (stat( -#endif - file->path, &file->_s) == -1) - { - return -1; - } -#endif - _tinydir_get_ext(file); - - file->is_dir = -#ifdef _MSC_VER - !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); -#else - S_ISDIR(file->_s.st_mode); -#endif - file->is_reg = -#ifdef _MSC_VER - !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || - ( - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && -#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) && -#endif -#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) && -#endif - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY)); -#else - S_ISREG(file->_s.st_mode); -#endif - - return 0; -} - -_TINYDIR_FUNC -int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i) -{ - if (dir == NULL || file == NULL) - { - errno = EINVAL; - return -1; - } - if (i >= dir->n_files) - { - errno = ENOENT; - return -1; - } - - memcpy(file, &dir->_files[i], sizeof(tinydir_file)); - _tinydir_get_ext(file); - - return 0; -} - -_TINYDIR_FUNC -int tinydir_open_subdir_n(tinydir_dir *dir, size_t i) -{ - _tinydir_char_t path[_TINYDIR_PATH_MAX]; - if (dir == NULL) - { - errno = EINVAL; - return -1; - } - if (i >= dir->n_files || !dir->_files[i].is_dir) - { - errno = ENOENT; - return -1; - } - - _tinydir_strcpy(path, dir->_files[i].path); - tinydir_close(dir); - if (tinydir_open_sorted(dir, path) == -1) - { - return -1; - } - - return 0; -} - -/* Open a single file given its path */ -_TINYDIR_FUNC -int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path) -{ - tinydir_dir dir; - int result = 0; - int found = 0; - _tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX]; - _tinydir_char_t file_name_buf[_TINYDIR_PATH_MAX]; - _tinydir_char_t *dir_name; - _tinydir_char_t *base_name; -#if (defined _MSC_VER || defined __MINGW32__) - _tinydir_char_t drive_buf[_TINYDIR_PATH_MAX]; - _tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX]; -#endif - - if (file == NULL || path == NULL || _tinydir_strlen(path) == 0) - { - errno = EINVAL; - return -1; - } - if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) - { - errno = ENAMETOOLONG; - return -1; - } - - /* Get the parent path */ -#if (defined _MSC_VER || defined __MINGW32__) -#if ((defined _MSC_VER) && (_MSC_VER >= 1400)) - errno = _tsplitpath_s( - path, - drive_buf, _TINYDIR_DRIVE_MAX, - dir_name_buf, _TINYDIR_FILENAME_MAX, - file_name_buf, _TINYDIR_FILENAME_MAX, - ext_buf, _TINYDIR_FILENAME_MAX); -#else - _tsplitpath( - path, - drive_buf, - dir_name_buf, - file_name_buf, - ext_buf); -#endif - - if (errno) - { - return -1; - } - -/* _splitpath_s not work fine with only filename and widechar support */ -#ifdef _UNICODE - if (drive_buf[0] == L'\xFEFE') - drive_buf[0] = '\0'; - if (dir_name_buf[0] == L'\xFEFE') - dir_name_buf[0] = '\0'; -#endif - - /* Emulate the behavior of dirname by returning "." for dir name if it's - empty */ - if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0') - { - _tinydir_strcpy(dir_name_buf, TINYDIR_STRING(".")); - } - /* Concatenate the drive letter and dir name to form full dir name */ - _tinydir_strcat(drive_buf, dir_name_buf); - dir_name = drive_buf; - /* Concatenate the file name and extension to form base name */ - _tinydir_strcat(file_name_buf, ext_buf); - base_name = file_name_buf; -#else - _tinydir_strcpy(dir_name_buf, path); - dir_name = dirname(dir_name_buf); - _tinydir_strcpy(file_name_buf, path); - base_name = basename(file_name_buf); -#endif - - /* Special case: if the path is a root dir, open the parent dir as the file */ -#if (defined _MSC_VER || defined __MINGW32__) - if (_tinydir_strlen(base_name) == 0) -#else - if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0) -#endif - { - memset(file, 0, sizeof * file); - file->is_dir = 1; - file->is_reg = 0; - _tinydir_strcpy(file->path, dir_name); - file->extension = file->path + _tinydir_strlen(file->path); - return 0; - } - - /* Open the parent directory */ - if (tinydir_open(&dir, dir_name) == -1) - { - return -1; - } - - /* Read through the parent directory and look for the file */ - while (dir.has_next) - { - if (tinydir_readfile(&dir, file) == -1) - { - result = -1; - goto bail; - } - if (_tinydir_strcmp(file->name, base_name) == 0) - { - /* File found */ - found = 1; - break; - } - tinydir_next(&dir); - } - if (!found) - { - result = -1; - errno = ENOENT; - } - -bail: - tinydir_close(&dir); - return result; -} - -_TINYDIR_FUNC -void _tinydir_get_ext(tinydir_file *file) -{ - _tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.')); - if (period == NULL) - { - file->extension = &(file->name[_tinydir_strlen(file->name)]); - } - else - { - file->extension = period + 1; - } -} - -_TINYDIR_FUNC -int _TINYDIR_CDECL _tinydir_file_cmp(const void *a, const void *b) -{ - const tinydir_file *fa = (const tinydir_file *)a; - const tinydir_file *fb = (const tinydir_file *)b; - if (fa->is_dir != fb->is_dir) - { - return -(fa->is_dir - fb->is_dir); - } - return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX); -} - -#ifndef _MSC_VER -#ifndef _TINYDIR_USE_READDIR -/* -The following authored by Ben Hutchings -from https://womble.decadent.org.uk/readdir_r-advisory.html -*/ -/* Calculate the required buffer size (in bytes) for directory * -* entries read from the given directory handle. Return -1 if this * -* this cannot be done. * -* * -* This code does not trust values of NAME_MAX that are less than * -* 255, since some systems (including at least HP-UX) incorrectly * -* define it to be a smaller value. */ -_TINYDIR_FUNC -size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp) -{ - long name_max; - size_t name_end; - /* parameter may be unused */ - (void)dirp; - -#if defined _TINYDIR_USE_FPATHCONF - name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX); - if (name_max == -1) -#if defined(NAME_MAX) - name_max = (NAME_MAX > 255) ? NAME_MAX : 255; -#else - return (size_t)(-1); -#endif -#elif defined(NAME_MAX) - name_max = (NAME_MAX > 255) ? NAME_MAX : 255; -#else -#error "buffer size for readdir_r cannot be determined" -#endif - name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1; - return (name_end > sizeof(struct _tinydir_dirent) ? - name_end : sizeof(struct _tinydir_dirent)); -} -#endif -#endif - -#ifdef __cplusplus -} -#endif - -# if defined (_MSC_VER) -# pragma warning(pop) -# endif - -#endif diff --git a/source/yugine.c b/source/yugine.c index fab64ed9..f6afafde 100644 --- a/source/yugine.c +++ b/source/yugine.c @@ -2,7 +2,13 @@ #include "script.h" #include +#include "physfs.h" + int main(int argc, char **argv) { + PHYSFS_init(argv[0]); + char *base = PHYSFS_getBaseDir(); + PHYSFS_setWriteDir(base); + PHYSFS_mount(base,NULL,0); script_startup(); // runs engine.js int argsize = 0; diff --git a/subprojects/chipmunk.wrap b/subprojects/chipmunk.wrap new file mode 100644 index 00000000..ab3e1914 --- /dev/null +++ b/subprojects/chipmunk.wrap @@ -0,0 +1,2 @@ +[wrap-redirect] +filename = qjs-chipmunk2d/subprojects/chipmunk.wrap