remove sokol, use sdl3
This commit is contained in:
25
meson.build
25
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
|
||||
|
||||
|
||||
@@ -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
|
||||
needs_exe_wrapper = false
|
||||
pkg_config_libdir = '/usr/local/lib64/pkgconfig'
|
||||
|
||||
@@ -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"];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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.",
|
||||
);
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5,16 +5,10 @@
|
||||
#include <stdint.h>
|
||||
#include <quickjs.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include "render.h"
|
||||
#include "HandmadeMath.h"
|
||||
#include <quickjs.h>
|
||||
#include "texture.h"
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -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 <stdint.h> /** imports uint8_t, uint16_t and uint32_t **/
|
||||
#ifndef GIF_MGET
|
||||
#include <stdlib.h>
|
||||
#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 **/
|
||||
2227
source/jsffi.c
2227
source/jsffi.c
File diff suppressed because it is too large
Load Diff
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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); \
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "render.h"
|
||||
|
||||
#include <sokol_app.h>
|
||||
#include <sokol/sokol_gfx.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -1,73 +1,7 @@
|
||||
#include "render.h"
|
||||
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include "sokol/sokol_glue.h"
|
||||
#include "HandmadeMath.h"
|
||||
#include <stdio.h>
|
||||
|
||||
sg_sampler std_sampler;
|
||||
sg_sampler tex_sampler;
|
||||
|
||||
viewstate globalview = {0};
|
||||
|
||||
#ifdef TRACY_ENABLE
|
||||
#include <tracy/TracyC.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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 <SDL3/SDL.h>
|
||||
|
||||
#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);
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "glad.h"
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
#include <tracy/TracyOpenGL.hpp>
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "script.h"
|
||||
#include "jsffi.h"
|
||||
#include "stb_ds.h"
|
||||
#include <sokol/sokol_time.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -11,8 +10,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <tracy/TracyC.h>
|
||||
|
||||
static JSContext *js = NULL;
|
||||
static JSRuntime *rt = NULL;
|
||||
|
||||
|
||||
311
source/texture.c
311
source/texture.c
@@ -1,7 +1,6 @@
|
||||
#include "texture.h"
|
||||
|
||||
#include "render.h"
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include <math.h>
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_write.h>
|
||||
@@ -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;
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
#ifndef TEXTURE_H
|
||||
#define TEXTURE_H
|
||||
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include "HandmadeMath.h"
|
||||
#include "render.h"
|
||||
#include <quickjs.h>
|
||||
|
||||
#include "stb_rect_pack.h"
|
||||
|
||||
#include "sokol_app.h"
|
||||
#include "sokol/util/sokol_imgui.h"
|
||||
#include <SDL3/SDL_render.h>
|
||||
|
||||
#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
|
||||
|
||||
|
||||
9
source/thirdparty/sokol/.editorconfig
vendored
9
source/thirdparty/sokol/.editorconfig
vendored
@@ -1,9 +0,0 @@
|
||||
root=true
|
||||
[**]
|
||||
indent_style=space
|
||||
indent_size=4
|
||||
trim_trailing_whitespace=true
|
||||
insert_final_newline=true
|
||||
|
||||
[*.yml]
|
||||
indent_size=2
|
||||
@@ -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
|
||||
@@ -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
|
||||
7
source/thirdparty/sokol/.gitignore
vendored
7
source/thirdparty/sokol/.gitignore
vendored
@@ -1,7 +0,0 @@
|
||||
.vscode/
|
||||
build/
|
||||
#>fips
|
||||
# this area is managed by fips, do not edit
|
||||
.fips-*
|
||||
*.pyc
|
||||
#<fips
|
||||
2692
source/thirdparty/sokol/CHANGELOG.md
vendored
2692
source/thirdparty/sokol/CHANGELOG.md
vendored
File diff suppressed because it is too large
Load Diff
22
source/thirdparty/sokol/LICENSE
vendored
22
source/thirdparty/sokol/LICENSE
vendored
@@ -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.
|
||||
406
source/thirdparty/sokol/README.md
vendored
406
source/thirdparty/sokol/README.md
vendored
@@ -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)
|
||||
|
||||
[](/../../actions/workflows/main.yml) [](/../../actions/workflows/gen_bindings.yml) [](https://github.com/floooh/sokol-zig/actions/workflows/main.yml) [](https://github.com/floooh/sokol-nim/actions/workflows/main.yml) [](https://github.com/floooh/sokol-odin/actions/workflows/main.yml)[](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.
|
||||
2
source/thirdparty/sokol/fips.yml
vendored
2
source/thirdparty/sokol/fips.yml
vendored
@@ -1,2 +0,0 @@
|
||||
exports:
|
||||
header-dirs: [ ".", "util" ]
|
||||
12097
source/thirdparty/sokol/sokol_app.h
vendored
12097
source/thirdparty/sokol/sokol_app.h
vendored
File diff suppressed because it is too large
Load Diff
867
source/thirdparty/sokol/sokol_args.h
vendored
867
source/thirdparty/sokol/sokol_args.h
vendored
@@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h> // 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 <string.h> // memset, strcmp
|
||||
#include <stdlib.h> // malloc, free
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#include <emscripten/emscripten.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 <assert.h>
|
||||
#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 */
|
||||
2612
source/thirdparty/sokol/sokol_audio.h
vendored
2612
source/thirdparty/sokol/sokol_audio.h
vendored
File diff suppressed because it is too large
Load Diff
2819
source/thirdparty/sokol/sokol_fetch.h
vendored
2819
source/thirdparty/sokol/sokol_fetch.h
vendored
File diff suppressed because it is too large
Load Diff
19540
source/thirdparty/sokol/sokol_gfx.h
vendored
19540
source/thirdparty/sokol/sokol_gfx.h
vendored
File diff suppressed because it is too large
Load Diff
162
source/thirdparty/sokol/sokol_glue.h
vendored
162
source/thirdparty/sokol/sokol_glue.h
vendored
@@ -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 <string.h> /* 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 */
|
||||
343
source/thirdparty/sokol/sokol_log.h
vendored
343
source/thirdparty/sokol/sokol_log.h
vendored
@@ -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 <stdint.h>
|
||||
|
||||
#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 <assert.h>
|
||||
#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 <stdlib.h> // abort
|
||||
#include <stdio.h> // fputs
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
#if defined(_SLOG_EMSCRIPTEN)
|
||||
#include <emscripten/emscripten.h>
|
||||
#elif defined(_SLOG_WINDOWS)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#elif defined(_SLOG_ANDROID)
|
||||
#include <android/log.h>
|
||||
#elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE)
|
||||
#include <syslog.h>
|
||||
#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
|
||||
319
source/thirdparty/sokol/sokol_time.h
vendored
319
source/thirdparty/sokol/sokol_time.h
vendored
@@ -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 <stdint.h>
|
||||
|
||||
#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 <string.h> /* memset */
|
||||
|
||||
#ifndef SOKOL_API_IMPL
|
||||
#define SOKOL_API_IMPL
|
||||
#endif
|
||||
#ifndef SOKOL_ASSERT
|
||||
#include <assert.h>
|
||||
#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 <windows.h>
|
||||
typedef struct {
|
||||
uint32_t initialized;
|
||||
LARGE_INTEGER freq;
|
||||
LARGE_INTEGER start;
|
||||
} _stm_state_t;
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
#include <mach/mach_time.h>
|
||||
typedef struct {
|
||||
uint32_t initialized;
|
||||
mach_timebase_info_data_t timebase;
|
||||
uint64_t start;
|
||||
} _stm_state_t;
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#include <emscripten/emscripten.h>
|
||||
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 <time.h>
|
||||
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 */
|
||||
|
||||
1148
source/thirdparty/sokol/util/sokol_color.h
vendored
1148
source/thirdparty/sokol/util/sokol_color.h
vendored
File diff suppressed because it is too large
Load Diff
4567
source/thirdparty/sokol/util/sokol_debugtext.h
vendored
4567
source/thirdparty/sokol/util/sokol_debugtext.h
vendored
File diff suppressed because it is too large
Load Diff
1789
source/thirdparty/sokol/util/sokol_fontstash.h
vendored
1789
source/thirdparty/sokol/util/sokol_fontstash.h
vendored
File diff suppressed because it is too large
Load Diff
4765
source/thirdparty/sokol/util/sokol_gfx_imgui.h
vendored
4765
source/thirdparty/sokol/util/sokol_gfx_imgui.h
vendored
File diff suppressed because it is too large
Load Diff
4329
source/thirdparty/sokol/util/sokol_gl.h
vendored
4329
source/thirdparty/sokol/util/sokol_gl.h
vendored
File diff suppressed because it is too large
Load Diff
3151
source/thirdparty/sokol/util/sokol_imgui.h
vendored
3151
source/thirdparty/sokol/util/sokol_imgui.h
vendored
File diff suppressed because it is too large
Load Diff
167
source/thirdparty/sokol/util/sokol_memtrack.h
vendored
167
source/thirdparty/sokol/util/sokol_memtrack.h
vendored
@@ -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 <stdint.h>
|
||||
#include <stddef.h> // 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 <stdlib.h> // malloc, free
|
||||
#include <string.h> // 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 */
|
||||
1431
source/thirdparty/sokol/util/sokol_shape.h
vendored
1431
source/thirdparty/sokol/util/sokol_shape.h
vendored
File diff suppressed because it is too large
Load Diff
5949
source/thirdparty/sokol/util/sokol_spine.h
vendored
5949
source/thirdparty/sokol/util/sokol_spine.h
vendored
File diff suppressed because it is too large
Load Diff
848
source/tinydir.h
848
source/tinydir.h
@@ -1,848 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2013-2021, tinydir authors:
|
||||
- Cong Xu
|
||||
- Lautis Sun
|
||||
- Baudouin Feildel
|
||||
- Andargor <andargor@yahoo.com>
|
||||
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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# pragma warning(push)
|
||||
# pragma warning (disable : 4996)
|
||||
#else
|
||||
# include <dirent.h>
|
||||
# include <libgen.h>
|
||||
# include <sys/stat.h>
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
#ifdef __MINGW32__
|
||||
# include <tchar.h>
|
||||
#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 <windows.h>
|
||||
# define _TINYDIR_PATH_MAX MAX_PATH
|
||||
#elif defined __linux__
|
||||
# include <limits.h>
|
||||
# ifdef PATH_MAX
|
||||
# define _TINYDIR_PATH_MAX PATH_MAX
|
||||
# endif
|
||||
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
# include <sys/param.h>
|
||||
# if defined(BSD)
|
||||
# include <limits.h>
|
||||
# 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 <unistd.h>
|
||||
#endif
|
||||
#if _BSD_SOURCE || _SVID_SOURCE || \
|
||||
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
||||
# define _TINYDIR_HAS_DIRFD
|
||||
# include <sys/types.h>
|
||||
#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 <ben@decadent.org.uk>
|
||||
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
|
||||
@@ -2,7 +2,13 @@
|
||||
#include "script.h"
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
|
||||
2
subprojects/chipmunk.wrap
Normal file
2
subprojects/chipmunk.wrap
Normal file
@@ -0,0 +1,2 @@
|
||||
[wrap-redirect]
|
||||
filename = qjs-chipmunk2d/subprojects/chipmunk.wrap
|
||||
Reference in New Issue
Block a user